one_punch.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use crate::nockapp::driver::*;
  2. use crate::nockapp::wire::Wire;
  3. use crate::nockapp::NockAppError;
  4. use crate::noun::slab::NounSlab;
  5. use either::Either::{self, Left, Right};
  6. use nockvm::noun::D;
  7. use nockvm_macros::tas;
  8. use tracing::{debug, error};
  9. pub enum OnePunchWire {
  10. Poke,
  11. }
  12. impl Wire for OnePunchWire {
  13. const VERSION: u64 = 1;
  14. const SOURCE: &'static str = "one-punch";
  15. }
  16. pub fn one_punch_man(data: NounSlab, op: Operation) -> IODriverFn {
  17. make_driver(|handle| async move {
  18. let wire = OnePunchWire::Poke.to_wire();
  19. let result = match op {
  20. Operation::Poke => Left(handle.poke(wire, data).await?),
  21. Operation::Peek => {
  22. debug!("poke_once_driver: peeking with {:?}", data);
  23. Right(handle.peek(data).await?)
  24. }
  25. };
  26. tokio::select! {
  27. res = handle_result(result, &op) => res,
  28. eff = handle.next_effect() => {
  29. handle_effect(eff, &handle).await
  30. },
  31. _ = tokio::time::sleep(tokio::time::Duration::from_secs(600)) => {
  32. //TODO what is a good timeout for tests?
  33. debug!("poke_once_driver: no effect received after 10 minutes");
  34. Err(NockAppError::Timeout)
  35. }
  36. }
  37. })
  38. }
  39. /// Handles the result of a poke or peek operation.
  40. ///
  41. /// Poke:
  42. /// - Ack: The poke operation was successful.
  43. /// - Nack: The poke operation failed.
  44. ///
  45. /// Peek:
  46. /// - Some(NounSlab): The peek operation was successful and returned a NounSlab.
  47. /// - None: The peek operation failed or returned no result.
  48. ///
  49. /// # Arguments
  50. ///
  51. /// * `result` - The result of the operation.
  52. /// * `op` - The operation type (Poke or Peek).
  53. ///
  54. /// # Returns
  55. ///
  56. /// A Result indicating success or failure of the operation.
  57. async fn handle_result(
  58. result: Either<PokeResult, Option<NounSlab>>,
  59. op: &Operation,
  60. ) -> Result<(), NockAppError> {
  61. match op {
  62. Operation::Poke => match result {
  63. Left(PokeResult::Ack) => {
  64. debug!("Poke successful");
  65. Ok(())
  66. }
  67. Left(PokeResult::Nack) => {
  68. debug!("Poke nacked");
  69. Err(NockAppError::PokeFailed)
  70. }
  71. Right(_) => {
  72. debug!("Unexpected result for poke operation");
  73. Err(NockAppError::UnexpectedResult)
  74. }
  75. },
  76. Operation::Peek => match result {
  77. Left(_) => {
  78. debug!("Unexpected result for peek operation");
  79. Err(NockAppError::UnexpectedResult)
  80. }
  81. Right(Some(peek_result)) => {
  82. debug!("Peek result: {:?}", peek_result);
  83. Ok(())
  84. }
  85. Right(_) => {
  86. debug!("Peek returned no result");
  87. Err(NockAppError::PeekFailed)
  88. }
  89. },
  90. }
  91. }
  92. /// Handles effects from the kernel.
  93. ///
  94. /// # Arguments
  95. ///
  96. /// * `eff` - The effect produced by the kernel.
  97. /// * `_handle` - The NockAppHandle (unused in this implementation).
  98. ///
  99. /// # Returns
  100. ///
  101. /// A Result indicating success or failure of handling the effect.
  102. async fn handle_effect(
  103. eff: Result<NounSlab, NockAppError>,
  104. _handle: &NockAppHandle,
  105. ) -> Result<(), NockAppError> {
  106. let eff = eff?;
  107. debug!("poke_once_driver: effect received: {:?}", eff);
  108. // Split out root bindings so they don't get dropped early
  109. let root = unsafe { eff.root() };
  110. debug!("poke_once_driver: root: {:?}", root);
  111. if root.is_atom() {
  112. error!("No effects were returned from one-shot poke.");
  113. return Err(NockAppError::PokeFailed);
  114. }
  115. let effect_cell = root.as_cell().unwrap_or_else(|err| {
  116. panic!(
  117. "Panicked with {err:?} at {}:{} (git sha: {:?})",
  118. file!(),
  119. line!(),
  120. option_env!("GIT_SHA")
  121. )
  122. });
  123. if unsafe { effect_cell.head().raw_equals(&D(tas!(b"npc"))) } {
  124. let npc_effect = effect_cell.tail();
  125. if let Ok(npc_effect_cell) = npc_effect.as_cell() {
  126. match npc_effect_cell
  127. .head()
  128. .as_atom()
  129. .unwrap_or_else(|err| {
  130. panic!(
  131. "Panicked with {err:?} at {}:{} (git sha: {:?})",
  132. file!(),
  133. line!(),
  134. option_env!("GIT_SHA")
  135. )
  136. })
  137. .as_u64()
  138. .expect("Failed to convert to u64")
  139. {
  140. tas!(b"gossip") => {
  141. // Ignore gossip data
  142. debug!("Ignoring gossip data");
  143. }
  144. tas!(b"request") => {
  145. debug!("Processing request effect");
  146. let request_data = npc_effect_cell.tail();
  147. debug!("Request data: {:?}", request_data);
  148. // handle.poke(create_response(request_data)).await?;
  149. }
  150. _ => debug!("Received unknown npc effect"),
  151. }
  152. }
  153. }
  154. Ok(())
  155. }