parent_port.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright (c) 2022 Microsoft, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/services/node/parent_port.h"
  5. #include <utility>
  6. #include "base/no_destructor.h"
  7. #include "gin/data_object_builder.h"
  8. #include "gin/handle.h"
  9. #include "shell/browser/api/message_port.h"
  10. #include "shell/common/gin_helper/dictionary.h"
  11. #include "shell/common/gin_helper/event_emitter_caller.h"
  12. #include "shell/common/node_includes.h"
  13. #include "shell/common/v8_value_serializer.h"
  14. #include "third_party/blink/public/common/messaging/transferable_message_mojom_traits.h"
  15. namespace electron {
  16. gin::WrapperInfo ParentPort::kWrapperInfo = {gin::kEmbedderNativeGin};
  17. ParentPort* ParentPort::GetInstance() {
  18. static base::NoDestructor<ParentPort> instance;
  19. return instance.get();
  20. }
  21. ParentPort::ParentPort() = default;
  22. ParentPort::~ParentPort() = default;
  23. void ParentPort::Initialize(blink::MessagePortDescriptor port) {
  24. port_ = std::move(port);
  25. connector_ = std::make_unique<mojo::Connector>(
  26. port_.TakeHandleToEntangleWithEmbedder(),
  27. mojo::Connector::SINGLE_THREADED_SEND,
  28. base::SingleThreadTaskRunner::GetCurrentDefault());
  29. connector_->PauseIncomingMethodCallProcessing();
  30. connector_->set_incoming_receiver(this);
  31. connector_->set_connection_error_handler(
  32. base::BindOnce(&ParentPort::Close, base::Unretained(this)));
  33. }
  34. void ParentPort::PostMessage(v8::Local<v8::Value> message_value) {
  35. if (!connector_closed_ && connector_ && connector_->is_valid()) {
  36. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  37. blink::TransferableMessage transferable_message;
  38. if (!electron::SerializeV8Value(isolate, message_value,
  39. &transferable_message)) {
  40. // SerializeV8Value sets an exception.
  41. return;
  42. }
  43. mojo::Message mojo_message =
  44. blink::mojom::TransferableMessage::WrapAsMessage(
  45. std::move(transferable_message));
  46. connector_->Accept(&mojo_message);
  47. }
  48. }
  49. void ParentPort::Close() {
  50. if (!connector_closed_ && connector_->is_valid()) {
  51. port_.GiveDisentangledHandle(connector_->PassMessagePipe());
  52. connector_ = nullptr;
  53. port_.Reset();
  54. connector_closed_ = true;
  55. }
  56. }
  57. void ParentPort::Start() {
  58. if (!connector_closed_ && connector_ && connector_->is_valid()) {
  59. connector_->ResumeIncomingMethodCallProcessing();
  60. }
  61. }
  62. void ParentPort::Pause() {
  63. if (!connector_closed_ && connector_ && connector_->is_valid()) {
  64. connector_->PauseIncomingMethodCallProcessing();
  65. }
  66. }
  67. bool ParentPort::Accept(mojo::Message* mojo_message) {
  68. blink::TransferableMessage message;
  69. if (!blink::mojom::TransferableMessage::DeserializeFromMessage(
  70. std::move(*mojo_message), &message)) {
  71. return false;
  72. }
  73. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  74. v8::HandleScope handle_scope(isolate);
  75. auto wrapped_ports =
  76. MessagePort::EntanglePorts(isolate, std::move(message.ports));
  77. v8::Local<v8::Value> message_value =
  78. electron::DeserializeV8Value(isolate, message);
  79. v8::Local<v8::Object> self;
  80. if (!GetWrapper(isolate).ToLocal(&self))
  81. return false;
  82. auto event = gin::DataObjectBuilder(isolate)
  83. .Set("data", message_value)
  84. .Set("ports", wrapped_ports)
  85. .Build();
  86. gin_helper::EmitEvent(isolate, self, "message", event);
  87. return true;
  88. }
  89. // static
  90. gin::Handle<ParentPort> ParentPort::Create(v8::Isolate* isolate) {
  91. return gin::CreateHandle(isolate, ParentPort::GetInstance());
  92. }
  93. // static
  94. gin::ObjectTemplateBuilder ParentPort::GetObjectTemplateBuilder(
  95. v8::Isolate* isolate) {
  96. return gin::Wrappable<ParentPort>::GetObjectTemplateBuilder(isolate)
  97. .SetMethod("postMessage", &ParentPort::PostMessage)
  98. .SetMethod("start", &ParentPort::Start)
  99. .SetMethod("pause", &ParentPort::Pause);
  100. }
  101. const char* ParentPort::GetTypeName() {
  102. return "ParentPort";
  103. }
  104. } // namespace electron
  105. namespace {
  106. void Initialize(v8::Local<v8::Object> exports,
  107. v8::Local<v8::Value> unused,
  108. v8::Local<v8::Context> context,
  109. void* priv) {
  110. v8::Isolate* isolate = context->GetIsolate();
  111. gin_helper::Dictionary dict(isolate, exports);
  112. dict.SetMethod("createParentPort", &electron::ParentPort::Create);
  113. }
  114. } // namespace
  115. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_utility_parent_port, Initialize)