@@ -11,6 +11,7 @@ namespace node {
1111namespace diagnostics_channel {
1212
1313using v8::Context;
14+ using v8::Function;
1415using v8::FunctionCallbackInfo;
1516using v8::HandleScope;
1617using v8::Isolate;
@@ -66,22 +67,49 @@ void BindingData::GetOrCreateChannelIndex(
6667 args.GetReturnValue ().Set (index);
6768}
6869
69- void BindingData::SetPublishCallback (const FunctionCallbackInfo<Value>& args) {
70+ void BindingData::LinkNativeChannel (const FunctionCallbackInfo<Value>& args) {
7071 Realm* realm = Realm::GetCurrent (args);
7172 BindingData* binding = realm->GetBindingData <BindingData>();
7273 CHECK_NOT_NULL (binding);
7374
7475 CHECK (args[0 ]->IsFunction ());
75- binding->publish_callback_ .Reset (realm->isolate (),
76- args[0 ].As <v8::Function>());
76+ Isolate* isolate = realm->isolate ();
77+ Local<Context> context = realm->context ();
78+ binding->link_callback_ .Reset (isolate, args[0 ].As <Function>());
79+
80+ // Resolve channels created before the link callback was available.
81+ for (uint32_t index : binding->pending_channels_ ) {
82+ for (const auto & pair : binding->channel_indices_ ) {
83+ if (pair.second == index) {
84+ Local<String> name =
85+ String::NewFromUtf8 (isolate, pair.first .c_str ()).ToLocalChecked ();
86+ Local<Value> argv[] = {name};
87+ Local<Value> result;
88+ if (binding->link_callback_ .Get (isolate)
89+ ->Call (context, v8::Undefined (isolate), 1 , argv)
90+ .ToLocal (&result) &&
91+ result->IsObject ()) {
92+ if (index >= binding->js_channels_ .size ()) {
93+ binding->js_channels_ .resize (index + 1 );
94+ }
95+ binding->js_channels_ [index].Reset (isolate, result.As <Object>());
96+ }
97+ break ;
98+ }
99+ }
100+ }
101+ binding->pending_channels_ .clear ();
77102}
78103
79104bool BindingData::PrepareForSerialization (Local<Context> context,
80105 SnapshotCreator* creator) {
81106 DCHECK_NULL (internal_field_info_);
82107 internal_field_info_ = InternalFieldInfoBase::New<InternalFieldInfo>(type ());
83108 internal_field_info_->subscribers = subscribers_.Serialize (context, creator);
84- publish_callback_.Reset ();
109+ link_callback_.Reset ();
110+ for (auto & global : js_channels_) {
111+ global.Reset ();
112+ }
85113 return true ;
86114}
87115
@@ -109,7 +137,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
109137 Isolate* isolate = isolate_data->isolate ();
110138 SetMethod (
111139 isolate, target, " getOrCreateChannelIndex" , GetOrCreateChannelIndex);
112- SetMethod (isolate, target, " setPublishCallback " , SetPublishCallback );
140+ SetMethod (isolate, target, " linkNativeChannel " , LinkNativeChannel );
113141}
114142
115143void BindingData::CreatePerContextProperties (Local<Object> target,
@@ -124,38 +152,72 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
124152void BindingData::RegisterExternalReferences (
125153 ExternalReferenceRegistry* registry) {
126154 registry->Register (GetOrCreateChannelIndex);
127- registry->Register (SetPublishCallback );
155+ registry->Register (LinkNativeChannel );
128156}
129157
130- Channel::Channel (BindingData* binding_data, uint32_t index, const char * name )
131- : binding_data_(binding_data), index_(index), name_(name) {}
158+ Channel::Channel (BindingData* binding_data, uint32_t index)
159+ : binding_data_(binding_data), index_(index) {}
132160
133161Channel Channel::Get (Environment* env, const char * name) {
134162 Realm* realm = env->principal_realm ();
135163 BindingData* binding = realm->GetBindingData <BindingData>();
136164 if (binding == nullptr ) {
137- return Channel (nullptr , 0 , name );
165+ return Channel (nullptr , 0 );
138166 }
139167 uint32_t index = binding->GetOrCreateChannelIndex (std::string (name));
140- return Channel (binding, index, name);
168+
169+ if (!binding->link_callback_ .IsEmpty ()) {
170+ if (index >= binding->js_channels_ .size ()) {
171+ binding->js_channels_ .resize (index + 1 );
172+ }
173+ if (binding->js_channels_ [index].IsEmpty ()) {
174+ Isolate* isolate = env->isolate ();
175+ HandleScope handle_scope (isolate);
176+ Local<Context> context = env->context ();
177+ Local<String> js_name =
178+ String::NewFromUtf8 (isolate, name).ToLocalChecked ();
179+ Local<Value> argv[] = {js_name};
180+ Local<Value> result;
181+ if (binding->link_callback_ .Get (isolate)
182+ ->Call (context, v8::Undefined (isolate), 1 , argv)
183+ .ToLocal (&result) &&
184+ result->IsObject ()) {
185+ binding->js_channels_ [index].Reset (isolate, result.As <Object>());
186+ }
187+ }
188+ } else {
189+ binding->pending_channels_ .push_back (index);
190+ }
191+
192+ return Channel (binding, index);
141193}
142194
143195void Channel::Publish (Environment* env, Local<Value> message) const {
144196 if (!HasSubscribers ()) return ;
145197
198+ if (binding_data_ == nullptr ) return ;
199+
146200 Isolate* isolate = env->isolate ();
147201 HandleScope handle_scope (isolate);
148202 Local<Context> context = env->context ();
149203 Context::Scope context_scope (context);
150204
151- if (binding_data_->publish_callback_ .IsEmpty ()) return ;
205+ if (index_ >= binding_data_->js_channels_ .size () ||
206+ binding_data_->js_channels_ [index_].IsEmpty ()) {
207+ return ;
208+ }
152209
153- Local<v8::Function> callback = binding_data_->publish_callback_ .Get (isolate);
154- Local<String> channel_name =
155- String::NewFromUtf8 (isolate, name_).ToLocalChecked ();
210+ Local<Object> js_channel =
211+ binding_data_->js_channels_ [index_].Get (isolate);
212+ Local<Value> publish_val;
213+ if (!js_channel->Get (context, FIXED_ONE_BYTE_STRING (isolate, " publish" ))
214+ .ToLocal (&publish_val) ||
215+ !publish_val->IsFunction ()) {
216+ return ;
217+ }
156218
157- Local<Value> argv[] = {channel_name, message};
158- USE (callback ->Call (context, v8::Undefined (isolate), 2 , argv));
219+ Local<Value> argv[] = {message};
220+ USE (publish_val. As <Function>() ->Call (context, js_channel, 1 , argv));
159221}
160222
161223} // namespace diagnostics_channel
0 commit comments