88
99from fastcs .controller import BaseController , Controller
1010from fastcs .controller_api import ControllerAPI
11- from fastcs .cs_methods import Command , Scan
11+ from fastcs .cs_methods import Command , Scan , ScanCallback
1212from fastcs .exceptions import FastCSError
1313from fastcs .logging import logger as _fastcs_logger
1414from fastcs .tracer import Tracer
@@ -36,36 +36,17 @@ def __init__(
3636 transports : Sequence [Transport ],
3737 loop : asyncio .AbstractEventLoop | None = None ,
3838 ):
39- self ._loop = loop or asyncio .get_event_loop ()
4039 self ._controller = controller
41-
42- self ._scan_tasks : set [asyncio .Task ] = set ()
43-
44- # these initialise the controller & build its APIs
45- self ._loop .run_until_complete (controller .initialise ())
46- self ._loop .run_until_complete (controller .attribute_initialise ())
47- validate_hinted_attributes (controller )
48- self .controller_api = build_controller_api (controller )
49-
50- self ._scan_coros , self ._initial_coros = (
51- self .controller_api .get_scan_and_initial_coros ()
52- )
53- self ._initial_coros .append (controller .connect )
54-
5540 self ._transports = transports
56- for transport in self ._transports :
57- transport .initialise (controller_api = self .controller_api , loop = self ._loop )
41+ self ._loop = loop or asyncio .get_event_loop ()
5842
59- def create_docs (self ) -> None :
60- for transport in self ._transports :
61- transport .create_docs ()
43+ self ._scan_coros : list [ScanCallback ] = []
44+ self ._initial_coros : list [ScanCallback ] = []
6245
63- def create_gui (self ) -> None :
64- for transport in self ._transports :
65- transport .create_gui ()
46+ self ._scan_tasks : set [asyncio .Task ] = set ()
6647
67- def run (self ):
68- serve = asyncio .ensure_future (self .serve ())
48+ def run (self , interactive : bool = True ):
49+ serve = asyncio .ensure_future (self .serve (interactive = interactive ))
6950
7051 self ._loop .add_signal_handler (signal .SIGINT , serve .cancel )
7152 self ._loop .add_signal_handler (signal .SIGTERM , serve .cancel )
@@ -100,7 +81,18 @@ def _stop_scan_tasks(self):
10081 except Exception as e :
10182 raise RuntimeError ("Unhandled exception in stop scan tasks" ) from e
10283
103- async def serve (self ) -> None :
84+ self ._scan_tasks .clear ()
85+
86+ async def serve (self , interactive : bool = True ) -> None :
87+ await self ._controller .initialise ()
88+ validate_hinted_attributes (self ._controller )
89+ self ._controller .connect_attribute_ios ()
90+
91+ self .controller_api = build_controller_api (self ._controller )
92+ self ._scan_coros , self ._initial_coros = (
93+ self .controller_api .get_scan_and_initial_coros ()
94+ )
95+
10496 context = {
10597 "controller" : self ._controller ,
10698 "controller_api" : self .controller_api ,
@@ -109,8 +101,9 @@ async def serve(self) -> None:
109101 ],
110102 }
111103
112- coros = []
104+ coros : list [ Coroutine ] = []
113105 for transport in self ._transports :
106+ transport .connect (controller_api = self .controller_api , loop = self ._loop )
114107 coros .append (transport .serve ())
115108 common_context = context .keys () & transport .context .keys ()
116109 if common_context :
@@ -122,14 +115,23 @@ async def serve(self) -> None:
122115 )
123116 context .update (transport .context )
124117
125- coros .append (self ._interactive_shell (context ))
118+ if interactive :
119+ coros .append (self ._interactive_shell (context ))
120+ else :
121+
122+ async def block_forever ():
123+ while True :
124+ await asyncio .sleep (1 )
125+
126+ coros .append (block_forever ())
126127
127128 logger .info (
128129 "Starting FastCS" ,
129130 controller = self ._controller ,
130131 transports = f"[{ ', ' .join (str (t ) for t in self ._transports )} ]" ,
131132 )
132133
134+ await self ._controller .connect ()
133135 await self ._run_initial_coros ()
134136 await self ._start_scan_tasks ()
135137
@@ -139,6 +141,10 @@ async def serve(self) -> None:
139141 pass
140142 except Exception as e :
141143 raise RuntimeError ("Unhandled exception in serve" ) from e
144+ finally :
145+ logger .info ("Shutting down FastCS" )
146+ self ._stop_scan_tasks ()
147+ await self ._controller .disconnect ()
142148
143149 async def _interactive_shell (self , context : dict [str , Any ]):
144150 """Spawn interactive shell in another thread and wait for it to complete."""
0 commit comments