@@ -4,6 +4,7 @@ use std::env::current_dir;
44use std:: path:: PathBuf ;
55use std:: sync:: Arc ;
66use std:: time:: Duration ;
7+ use tokio:: sync:: Mutex ;
78
89use arrow:: pyarrow:: { FromPyArrow , ToPyArrow } ;
910use dora_download:: download_file;
@@ -135,7 +136,7 @@ impl Node {
135136
136137 Ok ( Node {
137138 events : Events {
138- inner : EventsInner :: Dora ( events) ,
139+ inner : Arc :: new ( Mutex :: new ( EventsInner :: Dora ( events) ) ) ,
139140 _cleanup_handle : cleanup_handle,
140141 } ,
141142 dataflow_id,
@@ -167,7 +168,7 @@ impl Node {
167168 /// :rtype: dict
168169 #[ pyo3( signature = ( timeout=None ) ) ]
169170 #[ allow( clippy:: should_implement_trait) ]
170- pub fn next ( & mut self , py : Python , timeout : Option < f32 > ) -> PyResult < Option < Py < PyDict > > > {
171+ pub fn next ( & self , py : Python , timeout : Option < f32 > ) -> PyResult < Option < Py < PyDict > > > {
171172 let event = py. allow_threads ( || self . events . recv ( timeout. map ( Duration :: from_secs_f32) ) ) ;
172173 if let Some ( event) = event {
173174 let dict = event
@@ -190,7 +191,7 @@ impl Node {
190191 ///
191192 /// :rtype: list[dict]
192193 #[ allow( clippy:: should_implement_trait) ]
193- pub fn drain ( & mut self , py : Python ) -> PyResult < Vec < Py < PyDict > > > {
194+ pub fn drain ( & self , py : Python ) -> PyResult < Vec < Py < PyDict > > > {
194195 let events = self
195196 . events
196197 . drain ( )
@@ -253,7 +254,7 @@ impl Node {
253254 /// :rtype: dict
254255 #[ pyo3( signature = ( timeout=None ) ) ]
255256 #[ allow( clippy:: should_implement_trait) ]
256- pub async fn recv_async ( & mut self , timeout : Option < f32 > ) -> PyResult < Option < Py < PyDict > > > {
257+ pub async fn recv_async ( & self , timeout : Option < f32 > ) -> PyResult < Option < Py < PyDict > > > {
257258 let event = self
258259 . events
259260 . recv_async_timeout ( timeout. map ( Duration :: from_secs_f32) )
@@ -264,6 +265,7 @@ impl Node {
264265 let dict = event
265266 . to_py_dict ( py)
266267 . context ( "Could not convert event into a dict" ) ?;
268+
267269 Ok ( Some ( dict) )
268270 } )
269271 } else {
@@ -284,7 +286,7 @@ impl Node {
284286 /// Default behaviour is to timeout after 2 seconds.
285287 ///
286288 /// :rtype: dict
287- pub fn __next__ ( & mut self , py : Python ) -> PyResult < Option < Py < PyDict > > > {
289+ pub fn __next__ ( & self , py : Python ) -> PyResult < Option < Py < PyDict > > > {
288290 self . next ( py, None )
289291 }
290292
@@ -324,7 +326,7 @@ impl Node {
324326 /// :rtype: None
325327 #[ pyo3( signature = ( output_id, data, metadata=None ) ) ]
326328 pub fn send_output (
327- & mut self ,
329+ & self ,
328330 output_id : String ,
329331 data : PyObject ,
330332 metadata : Option < Bound < ' _ , PyDict > > ,
@@ -356,7 +358,7 @@ impl Node {
356358 /// This method returns the parsed dataflow YAML file.
357359 ///
358360 /// :rtype: dict
359- pub fn dataflow_descriptor ( & mut self , py : Python ) -> eyre:: Result < PyObject > {
361+ pub fn dataflow_descriptor ( & self , py : Python ) -> eyre:: Result < PyObject > {
360362 Ok (
361363 pythonize:: pythonize ( py, & self . node . get_mut ( ) . dataflow_descriptor ( ) ?)
362364 . map ( |x| x. unbind ( ) ) ?,
@@ -366,7 +368,7 @@ impl Node {
366368 /// Returns the node configuration.
367369 ///
368370 /// :rtype: dict
369- pub fn node_config ( & mut self , py : Python ) -> eyre:: Result < PyObject > {
371+ pub fn node_config ( & self , py : Python ) -> eyre:: Result < PyObject > {
370372 Ok ( pythonize:: pythonize ( py, & self . node . get_mut ( ) . node_config ( ) ) . map ( |x| x. unbind ( ) ) ?)
371373 }
372374
@@ -382,10 +384,7 @@ impl Node {
382384 ///
383385 /// :type subscription: dora.Ros2Subscription
384386 /// :rtype: None
385- pub fn merge_external_events (
386- & mut self ,
387- subscription : & mut Ros2Subscription ,
388- ) -> eyre:: Result < ( ) > {
387+ pub fn merge_external_events ( & self , subscription : & mut Ros2Subscription ) -> eyre:: Result < ( ) > {
389388 let subscription = subscription. into_stream ( ) ?;
390389 let stream = futures:: stream:: poll_fn ( move |cx| {
391390 let s = subscription. as_stream ( ) . map ( |item| {
@@ -404,12 +403,13 @@ impl Node {
404403 } ) ;
405404
406405 // take out the event stream and temporarily replace it with a dummy
406+ let mut inner = self . events . inner . blocking_lock ( ) ;
407407 let events = std:: mem:: replace (
408- & mut self . events . inner ,
408+ & mut * inner,
409409 EventsInner :: Merged ( Box :: new ( futures:: stream:: empty ( ) ) ) ,
410410 ) ;
411411 // update self.events with the merged stream
412- self . events . inner = EventsInner :: Merged ( events. merge_external_send ( Box :: pin ( stream) ) ) ;
412+ * inner = EventsInner :: Merged ( events. merge_external_send ( Box :: pin ( stream) ) ) ;
413413
414414 Ok ( ( ) )
415415 }
@@ -424,13 +424,14 @@ fn err_to_pyany(err: eyre::Report, gil: Python<'_>) -> Py<PyAny> {
424424}
425425
426426struct Events {
427- inner : EventsInner ,
427+ inner : Arc < Mutex < EventsInner > > ,
428428 _cleanup_handle : NodeCleanupHandle ,
429429}
430430
431431impl Events {
432- fn recv ( & mut self , timeout : Option < Duration > ) -> Option < PyEvent > {
433- let event = match & mut self . inner {
432+ fn recv ( & self , timeout : Option < Duration > ) -> Option < PyEvent > {
433+ let mut inner = self . inner . blocking_lock ( ) ;
434+ let event = match & mut * inner {
434435 EventsInner :: Dora ( events) => match timeout {
435436 Some ( timeout) => events. recv_timeout ( timeout) . map ( MergedEvent :: Dora ) ,
436437 None => events. recv ( ) . map ( MergedEvent :: Dora ) ,
@@ -440,8 +441,9 @@ impl Events {
440441 event. map ( |event| PyEvent { event } )
441442 }
442443
443- fn try_recv ( & mut self ) -> Result < PyEvent , TryRecvError > {
444- let event = match & mut self . inner {
444+ fn try_recv ( & self ) -> Result < PyEvent , TryRecvError > {
445+ let mut inner = self . inner . blocking_lock ( ) ;
446+ let event = match & mut * inner {
445447 EventsInner :: Dora ( events) => events. try_recv ( ) . map ( MergedEvent :: Dora ) ,
446448 EventsInner :: Merged ( _events) => {
447449 todo ! ( "try_recv on external event stream is not yet implemented!" )
@@ -450,8 +452,9 @@ impl Events {
450452 event. map ( |event| PyEvent { event } )
451453 }
452454
453- async fn recv_async_timeout ( & mut self , timeout : Option < Duration > ) -> Option < PyEvent > {
454- let event = match & mut self . inner {
455+ async fn recv_async_timeout ( & self , timeout : Option < Duration > ) -> Option < PyEvent > {
456+ let mut inner = self . inner . lock ( ) . await ;
457+ let event = match & mut * inner {
455458 EventsInner :: Dora ( events) => match timeout {
456459 Some ( timeout) => events
457460 . recv_async_timeout ( timeout)
@@ -464,8 +467,9 @@ impl Events {
464467 event. map ( |event| PyEvent { event } )
465468 }
466469
467- fn drain ( & mut self ) -> Option < Vec < PyEvent > > {
468- match & mut self . inner {
470+ fn drain ( & self ) -> Option < Vec < PyEvent > > {
471+ let mut inner = self . inner . blocking_lock ( ) ;
472+ match & mut * inner {
469473 EventsInner :: Dora ( events) => match events. drain ( ) {
470474 Some ( items) => {
471475 return Some (
@@ -485,7 +489,8 @@ impl Events {
485489 }
486490
487491 fn is_empty ( & self ) -> bool {
488- match & self . inner {
492+ let inner = self . inner . blocking_lock ( ) ;
493+ match & * inner {
489494 EventsInner :: Dora ( events) => events. is_empty ( ) ,
490495 EventsInner :: Merged ( _events) => {
491496 todo ! ( "is_empty on external event stream is not yet implemented!" )
0 commit comments