This repository has been archived by the owner on Jan 4, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 114
Add protocol.registerStreamProtocol #507
Open
olizilla
wants to merge
9
commits into
brave:master
Choose a base branch
from
tableflip:feature/register-stream-protocol
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
5429ec6
Port registerStreamProtocol from electron
olizilla 4a0aeea
WIP expose registerStreamProtocol to extensions
olizilla 8f016a3
WIP buffering stream impl
olizilla f3b36ba
adds readable ipc stream
alanshaw e18e57a
removes comment
alanshaw 194c7c2
removes unused code
alanshaw c7c8a8c
fixes linter warnings
alanshaw 5c42c5d
supports null data
alanshaw a3d43c8
Remove merge note code comment
olizilla File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright (c) 2017 GitHub, Inc. | ||
// Use of this source code is governed by the MIT license that can be | ||
// found in the LICENSE file. | ||
#include <string> | ||
#include <utility> | ||
|
||
#include "atom/browser/api/event_subscriber.h" | ||
#include "atom/common/native_mate_converters/callback.h" | ||
|
||
namespace { | ||
|
||
// A FunctionTemplate lifetime is bound to the v8 context, so it can be safely | ||
// stored as a global here since there's only one for the main process. | ||
v8::Global<v8::FunctionTemplate> g_cached_template; | ||
|
||
struct JSHandlerData { | ||
JSHandlerData(v8::Isolate* isolate, | ||
mate::internal::EventSubscriberBase* subscriber) | ||
: handle_(isolate, v8::External::New(isolate, this)), | ||
subscriber_(subscriber) { | ||
handle_.SetWeak(this, GC, v8::WeakCallbackType::kFinalizer); | ||
} | ||
|
||
static void GC(const v8::WeakCallbackInfo<JSHandlerData>& data) { | ||
delete data.GetParameter(); | ||
} | ||
|
||
v8::Global<v8::External> handle_; | ||
mate::internal::EventSubscriberBase* subscriber_; | ||
}; | ||
|
||
void InvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { | ||
v8::Locker locker(info.GetIsolate()); | ||
v8::HandleScope handle_scope(info.GetIsolate()); | ||
v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); | ||
v8::Context::Scope context_scope(context); | ||
mate::Arguments args(info); | ||
v8::Local<v8::Value> handler, event; | ||
args.GetNext(&handler); | ||
args.GetNext(&event); | ||
DCHECK(handler->IsExternal()); | ||
DCHECK(event->IsString()); | ||
JSHandlerData* handler_data = static_cast<JSHandlerData*>( | ||
v8::Local<v8::External>::Cast(handler)->Value()); | ||
handler_data->subscriber_->EventEmitted(mate::V8ToString(event), &args); | ||
} | ||
|
||
} // namespace | ||
|
||
namespace mate { | ||
|
||
namespace internal { | ||
|
||
EventSubscriberBase::EventSubscriberBase(v8::Isolate* isolate, | ||
v8::Local<v8::Object> emitter) | ||
: isolate_(isolate), emitter_(isolate, emitter) { | ||
if (g_cached_template.IsEmpty()) { | ||
g_cached_template = v8::Global<v8::FunctionTemplate>( | ||
isolate_, v8::FunctionTemplate::New(isolate_, InvokeCallback)); | ||
} | ||
} | ||
|
||
EventSubscriberBase::~EventSubscriberBase() { | ||
if (!isolate_) { | ||
return; | ||
} | ||
RemoveAllListeners(); | ||
emitter_.Reset(); | ||
DCHECK_EQ(js_handlers_.size(), 0); | ||
} | ||
|
||
void EventSubscriberBase::On(const std::string& event_name) { | ||
DCHECK(js_handlers_.find(event_name) == js_handlers_.end()); | ||
v8::Locker locker(isolate_); | ||
v8::Isolate::Scope isolate_scope(isolate_); | ||
v8::HandleScope handle_scope(isolate_); | ||
auto fn_template = g_cached_template.Get(isolate_); | ||
auto event = mate::StringToV8(isolate_, event_name); | ||
auto js_handler_data = new JSHandlerData(isolate_, this); | ||
v8::Local<v8::Value> fn = internal::BindFunctionWith( | ||
isolate_, isolate_->GetCurrentContext(), fn_template->GetFunction(), | ||
js_handler_data->handle_.Get(isolate_), event); | ||
js_handlers_.insert( | ||
std::make_pair(event_name, v8::Global<v8::Value>(isolate_, fn))); | ||
internal::ValueVector converted_args = {event, fn}; | ||
internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_), "on", | ||
&converted_args); | ||
} | ||
|
||
void EventSubscriberBase::Off(const std::string& event_name) { | ||
v8::Locker locker(isolate_); | ||
v8::Isolate::Scope isolate_scope(isolate_); | ||
v8::HandleScope handle_scope(isolate_); | ||
auto js_handler = js_handlers_.find(event_name); | ||
DCHECK(js_handler != js_handlers_.end()); | ||
RemoveListener(js_handler); | ||
} | ||
|
||
void EventSubscriberBase::RemoveAllListeners() { | ||
v8::Locker locker(isolate_); | ||
v8::Isolate::Scope isolate_scope(isolate_); | ||
v8::HandleScope handle_scope(isolate_); | ||
while (!js_handlers_.empty()) { | ||
RemoveListener(js_handlers_.begin()); | ||
} | ||
} | ||
|
||
std::map<std::string, v8::Global<v8::Value>>::iterator | ||
EventSubscriberBase::RemoveListener( | ||
std::map<std::string, v8::Global<v8::Value>>::iterator it) { | ||
internal::ValueVector args = {StringToV8(isolate_, it->first), | ||
it->second.Get(isolate_)}; | ||
internal::CallMethodWithArgs( | ||
isolate_, v8::Local<v8::Object>::Cast(emitter_.Get(isolate_)), | ||
"removeListener", &args); | ||
it->second.Reset(); | ||
return js_handlers_.erase(it); | ||
} | ||
|
||
} // namespace internal | ||
|
||
} // namespace mate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright (c) 2017 GitHub, Inc. | ||
// Use of this source code is governed by the MIT license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef ATOM_BROWSER_API_EVENT_SUBSCRIBER_H_ | ||
#define ATOM_BROWSER_API_EVENT_SUBSCRIBER_H_ | ||
|
||
#include <map> | ||
#include <memory> | ||
#include <string> | ||
#include <utility> | ||
|
||
#include "atom/common/api/event_emitter_caller.h" | ||
#include "base/synchronization/lock.h" | ||
#include "content/public/browser/browser_thread.h" | ||
#include "native_mate/native_mate/arguments.h" | ||
|
||
namespace mate { | ||
|
||
namespace internal { | ||
|
||
class EventSubscriberBase { | ||
public: | ||
EventSubscriberBase(v8::Isolate* isolate, v8::Local<v8::Object> emitter); | ||
virtual ~EventSubscriberBase(); | ||
virtual void EventEmitted(const std::string& event_name, | ||
mate::Arguments* args) = 0; | ||
|
||
protected: | ||
void On(const std::string& event_name); | ||
void Off(const std::string& event_name); | ||
void RemoveAllListeners(); | ||
|
||
private: | ||
std::map<std::string, v8::Global<v8::Value>>::iterator RemoveListener( | ||
std::map<std::string, v8::Global<v8::Value>>::iterator it); | ||
|
||
v8::Isolate* isolate_; | ||
v8::Global<v8::Object> emitter_; | ||
std::map<std::string, v8::Global<v8::Value>> js_handlers_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(EventSubscriberBase); | ||
}; | ||
|
||
} // namespace internal | ||
|
||
template <typename HandlerType> | ||
class EventSubscriber : internal::EventSubscriberBase { | ||
public: | ||
using EventCallback = void (HandlerType::*)(mate::Arguments* args); | ||
// Alias to unique_ptr with deleter. | ||
using unique_ptr = std::unique_ptr<EventSubscriber<HandlerType>, | ||
void (*)(EventSubscriber<HandlerType>*)>; | ||
// EventSubscriber should only be created/deleted in the main thread since it | ||
// communicates with the V8 engine. This smart pointer makes it simpler to | ||
// bind the lifetime of EventSubscriber with a class whose lifetime is managed | ||
// by a non-UI thread. | ||
class SafePtr : public unique_ptr { | ||
public: | ||
SafePtr() : SafePtr(nullptr) {} | ||
explicit SafePtr(EventSubscriber<HandlerType>* ptr) | ||
: unique_ptr(ptr, Deleter) {} | ||
|
||
private: | ||
// Custom deleter that schedules destructor invocation to the main thread. | ||
static void Deleter(EventSubscriber<HandlerType>* ptr) { | ||
DCHECK( | ||
!::content::BrowserThread::CurrentlyOn(::content::BrowserThread::UI)); | ||
DCHECK(ptr); | ||
// Acquire handler lock and reset handler_ to ensure that any new events | ||
// emitted will be ignored after this function returns | ||
base::AutoLock auto_lock(ptr->handler_lock_); | ||
ptr->handler_ = nullptr; | ||
content::BrowserThread::PostTask( | ||
content::BrowserThread::UI, FROM_HERE, | ||
base::Bind( | ||
[](EventSubscriber<HandlerType>* subscriber) { | ||
delete subscriber; | ||
}, | ||
ptr)); | ||
} | ||
}; | ||
|
||
EventSubscriber(HandlerType* handler, | ||
v8::Isolate* isolate, | ||
v8::Local<v8::Object> emitter) | ||
: EventSubscriberBase(isolate, emitter), handler_(handler) { | ||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI); | ||
} | ||
|
||
void On(const std::string& event, EventCallback callback) { | ||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI); | ||
EventSubscriberBase::On(event); | ||
callbacks_.insert(std::make_pair(event, callback)); | ||
} | ||
|
||
void Off(const std::string& event) { | ||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI); | ||
EventSubscriberBase::Off(event); | ||
DCHECK(callbacks_.find(event) != callbacks_.end()); | ||
callbacks_.erase(callbacks_.find(event)); | ||
} | ||
|
||
void RemoveAllListeners() { | ||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI); | ||
EventSubscriberBase::RemoveAllListeners(); | ||
callbacks_.clear(); | ||
} | ||
|
||
private: | ||
void EventEmitted(const std::string& event_name, | ||
mate::Arguments* args) override { | ||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI); | ||
base::AutoLock auto_lock(handler_lock_); | ||
if (!handler_) { | ||
// handler_ was probably destroyed by another thread and we should not | ||
// access it. | ||
return; | ||
} | ||
auto it = callbacks_.find(event_name); | ||
if (it != callbacks_.end()) { | ||
auto method = it->second; | ||
(handler_->*method)(args); | ||
} | ||
} | ||
|
||
HandlerType* handler_; | ||
base::Lock handler_lock_; | ||
std::map<std::string, EventCallback> callbacks_; | ||
}; | ||
|
||
} // namespace mate | ||
|
||
#endif // ATOM_BROWSER_API_EVENT_SUBSCRIBER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, that can go, it's just a left over from porting electron/electron#11008