event_subscriber.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright (c) 2017 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include <string>
  5. #include "atom/browser/api/event_subscriber.h"
  6. #include "atom/common/native_mate_converters/callback.h"
  7. namespace {
  8. // A FunctionTemplate lifetime is bound to the v8 context, so it can be safely
  9. // stored as a global here since there's only one for the main process.
  10. v8::Global<v8::FunctionTemplate> g_cached_template;
  11. struct JSHandlerData {
  12. JSHandlerData(v8::Isolate* isolate,
  13. mate::internal::EventSubscriberBase* subscriber)
  14. : handle_(isolate, v8::External::New(isolate, this)),
  15. subscriber_(subscriber) {
  16. handle_.SetWeak(this, GC, v8::WeakCallbackType::kFinalizer);
  17. }
  18. static void GC(const v8::WeakCallbackInfo<JSHandlerData>& data) {
  19. delete data.GetParameter();
  20. }
  21. v8::Global<v8::External> handle_;
  22. mate::internal::EventSubscriberBase* subscriber_;
  23. };
  24. void InvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
  25. v8::Locker locker(info.GetIsolate());
  26. v8::HandleScope handle_scope(info.GetIsolate());
  27. v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
  28. v8::Context::Scope context_scope(context);
  29. mate::Arguments args(info);
  30. v8::Local<v8::Value> handler, event;
  31. args.GetNext(&handler);
  32. args.GetNext(&event);
  33. DCHECK(handler->IsExternal());
  34. DCHECK(event->IsString());
  35. JSHandlerData* handler_data = static_cast<JSHandlerData*>(
  36. v8::Local<v8::External>::Cast(handler)->Value());
  37. handler_data->subscriber_->EventEmitted(mate::V8ToString(event), &args);
  38. }
  39. } // namespace
  40. namespace mate {
  41. namespace internal {
  42. EventSubscriberBase::EventSubscriberBase(v8::Isolate* isolate,
  43. v8::Local<v8::Object> emitter)
  44. : isolate_(isolate), emitter_(isolate, emitter) {
  45. if (g_cached_template.IsEmpty()) {
  46. g_cached_template = v8::Global<v8::FunctionTemplate>(
  47. isolate_, v8::FunctionTemplate::New(isolate_, InvokeCallback));
  48. }
  49. }
  50. EventSubscriberBase::~EventSubscriberBase() {
  51. if (!isolate_) {
  52. return;
  53. }
  54. RemoveAllListeners();
  55. emitter_.Reset();
  56. DCHECK_EQ(js_handlers_.size(), 0u);
  57. }
  58. void EventSubscriberBase::On(const std::string& event_name) {
  59. DCHECK(js_handlers_.find(event_name) == js_handlers_.end());
  60. v8::Locker locker(isolate_);
  61. v8::Isolate::Scope isolate_scope(isolate_);
  62. v8::HandleScope handle_scope(isolate_);
  63. auto fn_template = g_cached_template.Get(isolate_);
  64. auto event = mate::StringToV8(isolate_, event_name);
  65. auto* js_handler_data = new JSHandlerData(isolate_, this);
  66. v8::Local<v8::Value> fn = internal::BindFunctionWith(
  67. isolate_, isolate_->GetCurrentContext(), fn_template->GetFunction(),
  68. js_handler_data->handle_.Get(isolate_), event);
  69. js_handlers_.insert(
  70. std::make_pair(event_name, v8::Global<v8::Value>(isolate_, fn)));
  71. internal::ValueVector converted_args = {event, fn};
  72. internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_), "on",
  73. &converted_args);
  74. }
  75. void EventSubscriberBase::Off(const std::string& event_name) {
  76. v8::Locker locker(isolate_);
  77. v8::Isolate::Scope isolate_scope(isolate_);
  78. v8::HandleScope handle_scope(isolate_);
  79. auto js_handler = js_handlers_.find(event_name);
  80. DCHECK(js_handler != js_handlers_.end());
  81. RemoveListener(js_handler);
  82. }
  83. void EventSubscriberBase::RemoveAllListeners() {
  84. v8::Locker locker(isolate_);
  85. v8::Isolate::Scope isolate_scope(isolate_);
  86. v8::HandleScope handle_scope(isolate_);
  87. while (!js_handlers_.empty()) {
  88. RemoveListener(js_handlers_.begin());
  89. }
  90. }
  91. std::map<std::string, v8::Global<v8::Value>>::iterator
  92. EventSubscriberBase::RemoveListener(
  93. std::map<std::string, v8::Global<v8::Value>>::iterator it) {
  94. internal::ValueVector args = {StringToV8(isolate_, it->first),
  95. it->second.Get(isolate_)};
  96. internal::CallMethodWithArgs(
  97. isolate_, v8::Local<v8::Object>::Cast(emitter_.Get(isolate_)),
  98. "removeListener", &args);
  99. it->second.Reset();
  100. return js_handlers_.erase(it);
  101. }
  102. } // namespace internal
  103. } // namespace mate