33import argparse
44import asyncio
55import logging
6+ import sys
67from collections .abc import Mapping
78from collections .abc import MutableMapping
89from pathlib import Path
1819logger = logging .getLogger (__name__ )
1920
2021
21- class CommandProtocol ( asyncio . Protocol ) :
22+ class Controller :
2223 command_parser = argparse .ArgumentParser (prog = "mockliveserver" )
2324 subparsers = command_parser .add_subparsers (dest = "command" )
2425
@@ -45,47 +46,43 @@ def __init__(
4546 server : asyncio .base_events .Server ,
4647 api_key_table : Mapping [str , set [str ]],
4748 file_replay_table : MutableMapping [tuple [Dataset , Schema ], ReplayProtocol ],
49+ loop : asyncio .AbstractEventLoop ,
4850 ) -> None :
4951 self ._server = server
5052 self ._api_key_table = api_key_table
5153 self ._file_replay_table = file_replay_table
52-
53- def eof_received (self ) -> bool | None :
54- self ._server .close ()
55- return super ().eof_received ()
56-
57- def data_received (self , data : bytes ) -> None :
58- logger .debug ("%d bytes from stdin" , len (data ))
59- try :
60- command_str = data .decode ("utf-8" )
61- except Exception :
62- logger .error ("error parsing command" )
63- raise
64-
65- for command in command_str .splitlines ():
66- params = self .command_parser .parse_args (command .split ())
67- command_func = getattr (self , f"_command_{ params .command } " , None )
68- if command_func is None :
69- raise ValueError (f"{ params .command } does not have a command handler" )
54+ self ._loop = loop
55+
56+ self ._read_task = loop .create_task (self ._read_commands ())
57+
58+ async def _read_commands (self ) -> None :
59+ while self ._server .is_serving ():
60+ line = await self ._loop .run_in_executor (None , sys .stdin .readline )
61+ self .data_received (line .strip ())
62+
63+ def data_received (self , command_str : str ) -> None :
64+ params = self .command_parser .parse_args (command_str .split ())
65+ command_func = getattr (self , f"_command_{ params .command } " , None )
66+ if command_func is None :
67+ raise ValueError (f"{ params .command } does not have a command handler" )
68+ else :
69+ logger .info ("received command: %s" , command_str )
70+ command_params = dict (params ._get_kwargs ())
71+ command_params .pop ("command" )
72+ try :
73+ command_func (** command_params )
74+ except Exception :
75+ logger .exception ("error processing command: %s" , params .command )
76+ print (f"nack: { command_str } " , flush = True )
7077 else :
71- logger .info ("received command: %s" , command )
72- command_params = dict (params ._get_kwargs ())
73- command_params .pop ("command" )
74- try :
75- command_func (** command_params )
76- except Exception :
77- logger .exception ("error processing command: %s" , params .command )
78- print (f"nack: { command } " , flush = True )
79- else :
80- print (f"ack: { command } " , flush = True )
81-
82- return super ().data_received (data )
78+ print (f"ack: { command_str } " , flush = True )
8379
8480 def _command_close (self , * _ : str ) -> None :
8581 """
8682 Close the server.
8783 """
88- self ._server .close ()
84+ self ._read_task .cancel ()
85+ self ._loop .call_soon (self ._server .close )
8986
9087 def _command_active_count (self , * _ : str ) -> None :
9188 """
0 commit comments