event.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. use std::boxed::Box;
  2. use std::collections::HashMap;
  3. use std::sync::{Arc, Mutex};
  4. use lazy_static::lazy_static;
  5. use once_cell::sync::Lazy;
  6. use web_view::Handle;
  7. /// An event handler.
  8. struct EventHandler {
  9. /// The on event callback.
  10. on_event: Box<dyn FnMut(Option<String>) + Send>,
  11. }
  12. type Listeners = Arc<Mutex<HashMap<String, EventHandler>>>;
  13. lazy_static! {
  14. static ref EMIT_FUNCTION_NAME: String = uuid::Uuid::new_v4().to_string();
  15. static ref EVENT_LISTENERS_OBJECT_NAME: String = uuid::Uuid::new_v4().to_string();
  16. static ref EVENT_QUEUE_OBJECT_NAME: String = uuid::Uuid::new_v4().to_string();
  17. }
  18. /// Gets the listeners map.
  19. fn listeners() -> &'static Listeners {
  20. static LISTENERS: Lazy<Listeners> = Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));
  21. &LISTENERS
  22. }
  23. /// the emit JS function name
  24. pub fn emit_function_name() -> String {
  25. EMIT_FUNCTION_NAME.to_string()
  26. }
  27. /// the event listeners JS object name
  28. pub fn event_listeners_object_name() -> String {
  29. EVENT_LISTENERS_OBJECT_NAME.to_string()
  30. }
  31. /// the event queue JS object name
  32. pub fn event_queue_object_name() -> String {
  33. EVENT_QUEUE_OBJECT_NAME.to_string()
  34. }
  35. /// Adds an event listener for JS events.
  36. pub fn listen<F: FnMut(Option<String>) + Send + 'static>(id: String, handler: F) {
  37. let mut l = listeners()
  38. .lock()
  39. .expect("Failed to lock listeners: listen()");
  40. l.insert(
  41. id,
  42. EventHandler {
  43. on_event: Box::new(handler),
  44. },
  45. );
  46. }
  47. /// Emits an event to JS.
  48. pub fn emit<T: 'static>(webview_handle: &Handle<T>, event: String, payload: Option<String>) {
  49. let salt = crate::salt::generate();
  50. let js_payload = if let Some(payload_str) = payload {
  51. payload_str
  52. } else {
  53. "void 0".to_string()
  54. };
  55. webview_handle
  56. .dispatch(move |_webview| {
  57. _webview.eval(&format!(
  58. "window['{}']({{type: '{}', payload: {}}}, '{}')",
  59. emit_function_name(),
  60. event.as_str(),
  61. js_payload,
  62. salt
  63. ))
  64. })
  65. .expect("Failed to dispatch JS from emit");
  66. }
  67. /// Triggers the given event with its payload.
  68. pub fn on_event(event: String, data: Option<String>) {
  69. let mut l = listeners()
  70. .lock()
  71. .expect("Failed to lock listeners: on_event()");
  72. if l.contains_key(&event) {
  73. let handler = l.get_mut(&event).expect("Failed to get mutable handler");
  74. (handler.on_event)(data);
  75. }
  76. }
  77. #[cfg(test)]
  78. mod test {
  79. use crate::event::*;
  80. use proptest::prelude::*;
  81. // dummy event handler function
  82. fn event_fn(s: Option<String>) {
  83. println!("{:?}", s);
  84. }
  85. proptest! {
  86. #![proptest_config(ProptestConfig::with_cases(10000))]
  87. #[test]
  88. // check to see if listen() is properly passing keys into the LISTENERS map
  89. fn listeners_check_key(e in "[a-z]+") {
  90. // clone e as the key
  91. let key = e.clone();
  92. // pass e and an dummy func into listen
  93. listen(e, event_fn);
  94. // lock mutex
  95. let l = listeners().lock().unwrap();
  96. // check if the generated key is in the map
  97. assert_eq!(l.contains_key(&key), true);
  98. }
  99. #[test]
  100. // check to see if listen inputs a handler function properly into the LISTENERS map.
  101. fn listeners_check_fn(e in "[a-z]+") {
  102. // clone e as the key
  103. let key = e.clone();
  104. // pass e and an dummy func into listen
  105. listen(e, event_fn);
  106. // lock mutex
  107. let mut l = listeners().lock().unwrap();
  108. // check if l contains key
  109. if l.contains_key(&key) {
  110. // grab key if it exists
  111. let handler = l.get_mut(&key);
  112. // check to see if we get back a handler or not
  113. match handler {
  114. // pass on Some(handler)
  115. Some(_) => assert!(true),
  116. // Fail on None
  117. None => assert!(false)
  118. }
  119. }
  120. }
  121. #[test]
  122. // check to see if on_event properly grabs the stored function from listen.
  123. fn check_on_event(e in "[a-z]+", d in "[a-z]+") {
  124. // clone e as the key
  125. let key = e.clone();
  126. // call listen with e and the event_fn dummy func
  127. listen(e.clone(), event_fn);
  128. // call on event with e and d.
  129. on_event(e, Some(d));
  130. // lock the mutex
  131. let l = listeners().lock().unwrap();
  132. // assert that the key is contained in the listeners map
  133. assert!(l.contains_key(&key));
  134. }
  135. }
  136. }