@@ -94,8 +94,6 @@ class Client:
94
94
in the middle of a RPC can break subsequent RPCs (from the same
95
95
client).
96
96
"""
97
- kernel_invariants = set ()
98
-
99
97
def __init__ (self , host , port , target_name = AutoTarget , timeout = None ):
100
98
self .__socket = socket .create_connection ((host , port ), timeout )
101
99
@@ -106,6 +104,7 @@ def __init__(self, host, port, target_name=AutoTarget, timeout=None):
106
104
self .__target_names = server_identification ["targets" ]
107
105
self .__description = server_identification ["description" ]
108
106
self .__selected_target = None
107
+ self .__valid_methods = set ()
109
108
if target_name is not None :
110
109
self .select_rpc_target (target_name )
111
110
except :
@@ -118,6 +117,7 @@ def select_rpc_target(self, target_name):
118
117
target_name = _validate_target_name (target_name , self .__target_names )
119
118
self .__socket .sendall ((target_name + "\n " ).encode ())
120
119
self .__selected_target = target_name
120
+ self .__valid_methods = self .__recv ()
121
121
122
122
def get_selected_target (self ):
123
123
"""Returns the selected target, or ``None`` if no target has been
@@ -173,6 +173,8 @@ def get_rpc_method_list(self):
173
173
return self .__do_action (obj )
174
174
175
175
def __getattr__ (self , name ):
176
+ if name not in self .__valid_methods :
177
+ raise AttributeError
176
178
def proxy (* args , ** kwargs ):
177
179
return self .__do_rpc (name , args , kwargs )
178
180
return proxy
@@ -187,8 +189,6 @@ class AsyncioClient:
187
189
Concurrent access from different asyncio tasks is supported; all calls
188
190
use a single lock.
189
191
"""
190
- kernel_invariants = set ()
191
-
192
192
def __init__ (self ):
193
193
self .__lock = asyncio .Lock ()
194
194
self .__reader = None
@@ -208,19 +208,21 @@ async def connect_rpc(self, host, port, target_name):
208
208
self .__target_names = server_identification ["targets" ]
209
209
self .__description = server_identification ["description" ]
210
210
self .__selected_target = None
211
+ self .__valid_methods = set ()
211
212
if target_name is not None :
212
- self .select_rpc_target (target_name )
213
+ await self .select_rpc_target (target_name )
213
214
except :
214
215
self .close_rpc ()
215
216
raise
216
217
217
- def select_rpc_target (self , target_name ):
218
+ async def select_rpc_target (self , target_name ):
218
219
"""Selects a RPC target by name. This function should be called
219
220
exactly once if the connection was created with ``target_name=None``.
220
221
"""
221
222
target_name = _validate_target_name (target_name , self .__target_names )
222
223
self .__writer .write ((target_name + "\n " ).encode ())
223
224
self .__selected_target = target_name
225
+ self .__valid_methods = await self .__recv ()
224
226
225
227
def get_selected_target (self ):
226
228
"""Returns the selected target, or ``None`` if no target has been
@@ -273,6 +275,8 @@ async def __do_rpc(self, name, args, kwargs):
273
275
self .__lock .release ()
274
276
275
277
def __getattr__ (self , name ):
278
+ if name not in self .__valid_methods :
279
+ raise AttributeError
276
280
async def proxy (* args , ** kwargs ):
277
281
res = await self .__do_rpc (name , args , kwargs )
278
282
return res
@@ -292,8 +296,6 @@ class BestEffortClient:
292
296
:param retry: Amount of time to wait between retries when reconnecting
293
297
in the background.
294
298
"""
295
- kernel_invariants = set ()
296
-
297
299
def __init__ (self , host , port , target_name ,
298
300
firstcon_timeout = 1.0 , retry = 5.0 ):
299
301
self .__host = host
@@ -303,6 +305,7 @@ def __init__(self, host, port, target_name,
303
305
304
306
self .__conretry_terminate = False
305
307
self .__socket = None
308
+ self .__valid_methods = set ()
306
309
try :
307
310
self .__coninit (firstcon_timeout )
308
311
except :
@@ -327,6 +330,7 @@ def __coninit(self, timeout):
327
330
target_name = _validate_target_name (self .__target_name ,
328
331
server_identification ["targets" ])
329
332
self .__socket .sendall ((target_name + "\n " ).encode ())
333
+ self .__valid_methods = self .__recv ()
330
334
331
335
def __start_conretry (self ):
332
336
self .__conretry_thread = threading .Thread (target = self .__conretry )
@@ -401,6 +405,8 @@ def __do_rpc(self, name, args, kwargs):
401
405
raise ValueError
402
406
403
407
def __getattr__ (self , name ):
408
+ if name not in self .__valid_methods :
409
+ raise AttributeError
404
410
def proxy (* args , ** kwargs ):
405
411
return self .__do_rpc (name , args , kwargs )
406
412
return proxy
@@ -558,6 +564,12 @@ async def _handle_connection_cr(self, reader, writer):
558
564
if callable (target ):
559
565
target = target ()
560
566
567
+ valid_methods = inspect .getmembers (target , inspect .ismethod )
568
+ valid_methods = {m [0 ] for m in valid_methods }
569
+ if self .builtin_terminate :
570
+ valid_methods .add ("terminate" )
571
+ writer .write ((pyon .encode (valid_methods ) + "\n " ).encode ())
572
+
561
573
while True :
562
574
line = await reader .readline ()
563
575
if not line :
0 commit comments