-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing chrome debugging on v10 #3411
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@Anzormumladze I understand your frustration when it comes to debugging with JS SDK. You are right, this is a well know issue (explained in detail here #491). We are hoping to fix it by investing in #2455. Please subscribe. I would also like to point out that leaving derogatory comments is against our code of conduct https://realm.io/conduct/. Please refrain from using foul language in the future. |
@kraenhansen You're doing an amazing work to get this out. Tell me if I can help with something, looking forward to fix this issue for our developer team. |
thanks for answering me back, I deleted all my comment and looking forward to seeing good news |
0b755ce
to
d1fe510
Compare
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.
I think you need to add the new network transport to Android.mk
.
src/js_app.hpp
Outdated
std::string user_agent_binding_info; | ||
auto user_agent_function = js::Object<T>::get_property(ctx, realm_constructor, "_createUserAgentDescription"); | ||
if (js::Value<T>::is_function(ctx, user_agent_function)) { | ||
auto result = js::Function<T>::call(ctx, js::Value<T>::to_function(ctx, user_agent_function), realm_constructor, 0, nullptr); | ||
user_agent_binding_info = js::Value<T>::validated_to_string(ctx, result); | ||
} | ||
else { | ||
// FIXME: When debugging RN apps, _createUserAgentDescription cannot be found |
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.
We will have to create a callback to the browser to get it to work. On the other hand, while debugging, it is not so important.
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.
That's a great point - I overlooked this.
It's probably not that interesting to know the version of the Chrome browser running this.
I wonder if there's a way to make object store not send any device information at all?
src/js_app.hpp
Outdated
std::string user_agent_binding_info; | ||
auto user_agent_function = js::Object<T>::get_property(ctx, realm_constructor, "_createUserAgentDescription"); | ||
if (js::Value<T>::is_function(ctx, user_agent_function)) { | ||
auto result = js::Function<T>::call(ctx, js::Value<T>::to_function(ctx, user_agent_function), realm_constructor, 0, nullptr); | ||
user_agent_binding_info = js::Value<T>::validated_to_string(ctx, result); | ||
} | ||
else { | ||
// FIXME: When debugging RN apps, _createUserAgentDescription cannot be found | ||
user_agent_binding_info = "N/A"; |
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.
user_agent_binding_info = "N/A"; | |
user_agent_binding_info = "RN debugging"; |
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.
I understand that this would be the case from a practical level, but if we had a bug in our extension code the _createUserAgentDescription
method might not be assigned and then I think it's misleading to send "RN debugging".
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.
I think it's a bit pessimistic to optimize for the case where we have bugs in our code. We should instead assume that the code works as intended and provide the most relevant UX to users.
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.
I think it's a bit pessimistic to optimize for the case where we have bugs in our code.
I disagree: In my opinion, making little to no assumption between effect (the function is undefined) and the potential cause (running in chrome debugger mode) which sometimes are unrelated (something didn't load properly), makes it easier to debug code. In other words, the link between cause and effect should be as direct as possible.
The suggested change is too specific to the situations that might be causing the function to be undefined. In my opinion, the "right" solution would be to provide an authoritative runtime check which determines is we're running in the chrome debugger mode, but I honestly see very little value in that, since these values likely wont be relevant to the developer through the MongoDB Realm admin dashboard anyway and it won't be trivial to provide meaningful values.
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.
I agree that an unambiguous check if the code is running in a debugger is better, but don't agree with the rest. I don't think a user will easily make the connection that "js-unknown" means a debugger, so is likely to be left with the impression that either our code or theirs is broken and doesn't correctly report the platform.
If this function is only unrefined in a debugger, then using that as a check, even if semantically incorrect, is better than providing a broken user experience.
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.
In pre-v10 we skipped setting it as object store didn't require it. With v10, it is now a requirement. You can say that we are doing more or less the same as before.
src/js_app.hpp
Outdated
@@ -185,6 +201,12 @@ void AppClass<T>::constructor(ContextType ctx, ObjectType this_object, Arguments | |||
config.platform_version = js::Value<T>::validated_to_string(ctx, Object::get_property(ctx, result_object, platform_version_name)); | |||
config.sdk_version = js::Value<T>::validated_to_string(ctx, Object::get_property(ctx, result_object, sdk_version_name)); | |||
} | |||
else { | |||
// FIXME: When debugging RN apps, _createPlatformDescription() cannot be found | |||
config.platform = "N/A"; |
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.
config.platform = "N/A"; | |
config.platform = "RN debugging"; |
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.
For context, this was how the previous react native SDK reported its platform:
https://github.com/mongodb/stitch-js-sdk/blob/310f0bd5af80f818cdfbc3caf1ae29ffa8e9c7cf/packages/react-native/core/src/core/auth/internal/StitchAuthImpl.ts#L141-L143
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.
Same as the other comment . I would suggest setting this to "js-unknown"
to follow the pattern used by the legacy SDK and at the same time signal that the platform isn't known at this point. It'll most likely be react native chrome debugging, but we're checking for the existence of a function and not actually that we're running in that environment.
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.
keep up the good work guys. Anxiously waiting for this bug fix ! @kneth @kraenhansen
If that was the case, I'm wondering why the integration tests are passing? I think it doesn't have to be added since it's a header and those are taken care of on a per directory level here: https://github.com/realm/realm-js/blob/master/react-native/android/src/main/jni/Android.mk#L95 |
b8f85c2
to
5e7a1da
Compare
src/js_app.hpp
Outdated
auto realm_constructor = js::Value<T>::validated_to_object(ctx, js::Object<T>::get_global(ctx, "Realm")); | ||
|
||
Protected<typename T::GlobalContext> protected_ctx(Context::get_global_context(ctx)); | ||
config.transport_generator = [protected_ctx] { |
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.
We should be using this syntax everywhere we have to protect the context
https://github.com/realm/realm-js/blob/master/src/js_types.hpp#L708
this helps with making sure we don't introduce unintentional bugs cause of the two ctx names existing in the same scope
src/js_app.hpp
Outdated
std::string user_agent_binding_info; | ||
auto user_agent_function = js::Object<T>::get_property(ctx, realm_constructor, "_createUserAgentDescription"); | ||
if (js::Value<T>::is_function(ctx, user_agent_function)) { | ||
auto result = js::Function<T>::call(ctx, js::Value<T>::to_function(ctx, user_agent_function), realm_constructor, 0, nullptr); | ||
user_agent_binding_info = js::Value<T>::validated_to_string(ctx, result); | ||
} | ||
else { | ||
// The `_createUserAgentDescription` method is undefined when chrome debugging a React Native app |
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.
this function needs to accommodate that it might get executed in RN environment and we should call it here
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.
I don't understand this comment ☝️ Can I get you to rephrase it?
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.
In the past, a sync session should be opened without setting user_agent_binding_info
so we silently skipped the call when the RN debugger was active: https://github.com/realm/realm-js/blob/v6/src/js_sync.hpp#L62-L65
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.
_createUserAgentDescription should be called or some other mechanism introduced so we are able to get the result we are looking for. Seems like _createUserAgentDescription should be changed to support when running under chrome debugger which is what the PR is fixing.
*/ | ||
|
||
/** | ||
* Provides an implementation of GenericNetworkTransport for use when the library is loaded in a runtime which doesn't provide the APIs required to perform network requests directly. |
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.
I don't see the need to implement this. we should be able to use the JSNetworkTransport.
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.
Can you provide an explanation to this? What makes you think it would be better to use the JSNetworkTransport
? That is basically just a wrapper around some JavaScript code which won't be loaded in the case of us running in chrome debugger mode. I see no advantage in trying to polyfill the _networkTransport
property from C++.
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.
The way I see it is we have JavaScriptNetworkTransport which is a generic class to do network requests. It should be possible to use it instead of defining a new one for the debug context. The way it works is it just needs a global.Realm._networkTransport.fetchWithCallbacks
in order to work.
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.
That was my initial thought as well. However it turned out to be way easier to implement an alternative specialisation of GenericNetworkTransport
than providing a polyfill for fetchWithCallbacks
implemented in C++. I'm sure you would have reached the same conclusion. From your comment, I don't see sufficient value in changing this approach and I'll leave it as is.
@@ -126,6 +126,7 @@ struct Value { | |||
static bool is_boolean(ContextType, const ValueType &); | |||
static bool is_constructor(ContextType, const ValueType &); | |||
static bool is_date(ContextType, const ValueType &); | |||
static bool is_error(ContextType, const ValueType &); |
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.
whenever we change the abstraction layer we need to handle it both for Nodejs and RN
@@ -85,6 +85,12 @@ inline bool jsc::Value::is_constructor(JSContextRef ctx, const JSValueRef &value | |||
return JSValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value); | |||
} | |||
|
|||
template<> | |||
inline bool jsc::Value::is_error(JSContextRef ctx, const JSValueRef &value) { |
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.
whenever we change the abstraction layer we need to handle it both for Nodejs and RN
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.
Thanks for catching this - I thought about it and forgot about it 🙂
src/js_app.hpp
Outdated
std::string user_agent_binding_info; | ||
auto user_agent_function = js::Object<T>::get_property(ctx, realm_constructor, "_createUserAgentDescription"); | ||
if (js::Value<T>::is_function(ctx, user_agent_function)) { | ||
auto result = js::Function<T>::call(ctx, js::Value<T>::to_function(ctx, user_agent_function), realm_constructor, 0, nullptr); | ||
user_agent_binding_info = js::Value<T>::validated_to_string(ctx, result); | ||
} | ||
else { | ||
// The `_createUserAgentDescription` method is undefined when chrome debugging a React Native app |
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.
_createUserAgentDescription should be called or some other mechanism introduced so we are able to get the result we are looking for. Seems like _createUserAgentDescription should be changed to support when running under chrome debugger which is what the PR is fixing.
src/js_app.hpp
Outdated
@@ -185,6 +200,12 @@ void AppClass<T>::constructor(ContextType ctx, ObjectType this_object, Arguments | |||
config.platform_version = js::Value<T>::validated_to_string(ctx, Object::get_property(ctx, result_object, platform_version_name)); | |||
config.sdk_version = js::Value<T>::validated_to_string(ctx, Object::get_property(ctx, result_object, sdk_version_name)); | |||
} | |||
else { | |||
// The `_createPlatformDescription` method is undefined when chrome debugging a React Native app |
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.
every method is undefined when chrome debugging a React Native app
. we should make the changes needed to be able to call it. Or there are other options to get this information when running in Chrome debug context
*/ | ||
|
||
/** | ||
* Provides an implementation of GenericNetworkTransport for use when the library is loaded in a runtime which doesn't provide the APIs required to perform network requests directly. |
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.
The way I see it is we have JavaScriptNetworkTransport which is a generic class to do network requests. It should be possible to use it instead of defining a new one for the debug context. The way it works is it just needs a global.Realm._networkTransport.fetchWithCallbacks
in order to work.
c82d5b5
to
c028109
Compare
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.
approving the changes since my comments are already worked on
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.
LGTM
I've added static members to the |
I found (and solved a bug) where fetching would cause a "EXC_BAD_ACCESS" (the function got called in a released context). |
@@ -624,6 +624,9 @@ RPCServer::~RPCServer() { | |||
m_objects.clear(); | |||
m_callbacks.clear(); | |||
|
|||
// Clear the Object Store App cache, to prevent instances from using the context which is going to be released. | |||
app::App::clear_cached_apps(); |
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.
I am a bit unsure if this is the right place to call it.
I'm unaware of another place in our code that gets called when we're "unloading" our library, but we could clear the object store app cache when we initialize instead? https://github.com/realm/realm-js/blob/master/src/jsc/jsc_init.cpp#L42
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.
I imagine the issue is when you reload the app, right? If so, I think it make sense to clear the cache as you shut down the RPC server.
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.
Correct. If it's not cleared before / after a reload object store might be reusing app instances that reference a context which has been garbage collected.
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.
👍
Co-authored-by: Kenneth Geisshirt <kenneth.geisshirt@mongodb.com>
Co-authored-by: Kenneth Geisshirt <kenneth.geisshirt@mongodb.com>
LGTM - merge at will! |
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.
In general: I think we should make an effort to document functions -- at least new ones -- with e.g., Doxygen-style headers to improve the general developer-friendlyness of the codebase.
Otherwise, good job; LGTM.
When can we expect this commit/version to be published on npm? |
@saivarunk it's out in v10.0.2. |
What, How & Why?
This closes #3358 and #3361 by
App
RPCNetworkTransport
implementation of theGenericNetworkTransport
provided by object store. This struct is statically provided a function (assigned by theRPCServer
when a session gets created), which calls back into the browser to execute fetch requests, ultimately on behalf of object store.Error
instances to propagate the stack when an error is thrown during an RPC call.☑️ ToDos
Compatibility
label is updated or copied from previous entryBreaking
label has been applied or is not necessary