You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

lib.rs 2.8 kB

3 years ago
3 years ago
3 years ago
3 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #![allow(clippy::borrow_deref_ref)] // clippy warns about code generated by #[pymethods]
  2. use arrow::pyarrow::PyArrowConvert;
  3. use dora_node_api::{DoraNode, EventStream};
  4. use dora_operator_api_python::{pydict_to_metadata, PyEvent};
  5. use eyre::Context;
  6. use pyo3::prelude::*;
  7. use pyo3::types::{PyBytes, PyDict};
  8. #[pyclass]
  9. pub struct Node {
  10. events: EventStream,
  11. node: DoraNode,
  12. }
  13. #[pymethods]
  14. impl Node {
  15. #[new]
  16. pub fn new() -> eyre::Result<Self> {
  17. let (node, events) = DoraNode::init_from_env()?;
  18. Ok(Node { events, node })
  19. }
  20. #[allow(clippy::should_implement_trait)]
  21. pub fn next(&mut self, py: Python) -> PyResult<Option<PyEvent>> {
  22. self.__next__(py)
  23. }
  24. pub fn __next__(&mut self, py: Python) -> PyResult<Option<PyEvent>> {
  25. let event = py.allow_threads(|| self.events.recv());
  26. Ok(event.map(PyEvent))
  27. }
  28. fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
  29. slf
  30. }
  31. pub fn send_output(
  32. &mut self,
  33. output_id: String,
  34. data: PyObject,
  35. metadata: Option<&PyDict>,
  36. py: Python,
  37. ) -> eyre::Result<()> {
  38. if let Ok(py_bytes) = data.downcast::<PyBytes>(py) {
  39. let data = py_bytes.as_bytes();
  40. self.send_output_slice(output_id, data.len(), data, metadata)
  41. } else if let Ok(arrow_array) = arrow::array::ArrayData::from_pyarrow(data.as_ref(py)) {
  42. if arrow_array.data_type() != &arrow::datatypes::DataType::UInt8 {
  43. eyre::bail!("only arrow arrays with data type `UInt8` are supported");
  44. }
  45. if arrow_array.buffers().len() != 1 {
  46. eyre::bail!("output arrow array must contain a single buffer");
  47. }
  48. let len = arrow_array.len();
  49. let slice = &arrow_array.buffer(0)[..len];
  50. self.send_output_slice(output_id, len, slice, metadata)
  51. } else {
  52. eyre::bail!("invalid `data` type, must by `PyBytes` or arrow array")
  53. }
  54. }
  55. }
  56. impl Node {
  57. fn send_output_slice(
  58. &mut self,
  59. output_id: String,
  60. len: usize,
  61. data: &[u8],
  62. metadata: Option<&PyDict>,
  63. ) -> eyre::Result<()> {
  64. let metadata = pydict_to_metadata(metadata)?;
  65. self.node
  66. .send_output(output_id.into(), metadata, len, |out| {
  67. out.copy_from_slice(data);
  68. })
  69. .wrap_err("failed to send output")
  70. }
  71. pub fn id(&self) -> String {
  72. self.node.id().to_string()
  73. }
  74. }
  75. #[pyfunction]
  76. fn start_runtime() -> eyre::Result<()> {
  77. dora_runtime::main().wrap_err("Dora Runtime raised an error.")
  78. }
  79. #[pymodule]
  80. fn dora(_py: Python, m: &PyModule) -> PyResult<()> {
  81. m.add_function(wrap_pyfunction!(start_runtime, m)?)?;
  82. m.add_class::<Node>().unwrap();
  83. Ok(())
  84. }

DORA (Dataflow-Oriented Robotic Architecture) is middleware designed to streamline and simplify the creation of AI-based robotic applications. It offers low latency, composable, and distributed datafl