Page MenuHomePhabricator

Implement CommServicesAuthMetadataEmitter native event emitter on iOS
ClosedPublic

Authored by marcin on Dec 14 2023, 4:56 AM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Thu, Nov 21, 4:30 AM
Unknown Object (File)
Mon, Nov 18, 10:53 PM
Subscribers

Details

Summary

This differential implements CommServicesAuthMetadataEmitter for iOS in such a way that it is callable from C++.

Test Plan
  1. Apply this patch: https://gist.github.com/marcinwasowicz/7f04bd592dd4a800adbc96b720e200b7. It creates js code to subscribe for auth metadata events and sends this event from C++ upon each draft update (contents of the event are just dummy strings).
  2. Build iOS app.
  3. Ensure that each time you write one letter you can see console.log with dummy auth metadata in native yarn dev terminal.

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Rebase to update commit message

React native requires that event emitter is an instance of a class. On the other hand in order to smoothly call this object from Rust we need static method. Therefore I decided to use Singleton pattern for Rust <-> C++ interop. Object that is available to for C++ and Rust is set when the first JS listener subscribes and is removed when the last listener unsubscribes. This way we ensure that Rust/C++ won't try to send event if value under sharedInstance might be invalid. All calls that access or mutate sharedInstance are synchronized on class level.

Reviewers can quickly and easily familiarise themselves with event emitter implementation on iOS by reading the doc: https://reactnative.dev/docs/native-modules-ios#sending-events-to-javascript.

native/ios/Comm/CommServicesAuthMetadataEmitter.mm
9 โ†—(On Diff #34633)

It might look uncommon to have interface declaration and implementation next to each other in a single file but in fact we don't need to expose CommServicesAuthMetadataIOSWrapper. If we want to call sendAuthMetadataToJS from Objective - C we can use the common C++ API so let's avoid creating unnecessary files and duplication the same API.

Have you tested sending events (calling sendAuthMetadataToJS) when there are no listeners? Looking at the code, it should work but I want to make sure it doesn't crash the app

React native requires that event emitter is an instance of a class. On the other hand in order to smoothly call this object from Rust we need static method. Therefore I decided to use Singleton pattern for Rust <-> C++ interop. Object that is available to for C++ and Rust is set when the first JS listener subscribes and is removed when the last listener unsubscribes. This way we ensure that Rust/C++ won't try to send event if value under sharedInstance might be invalid. All calls that access or mutate sharedInstance are synchronized on class level.

That makes sense

native/ios/Comm/CommServicesAuthMetadataEmitter.mm
9 โ†—(On Diff #34633)

It's not that uncommon ๐Ÿ˜‰ I've seen this pattern already in some RN-related code and it makes sense here

13โ€“15 โ†—(On Diff #34633)

What about sendAccessTokenToJS: ... withUserID: ... withDeviceID?

Initially, I got confused because I understood sendToJSAccessToken as "send something to JS-based access token" ๐Ÿ˜…

varun added inline comments.
native/ios/Comm/CommServicesAuthMetadataEmitter.mm
13โ€“15 โ†—(On Diff #34633)

+1

  1. Rename Obj-C method.
  2. Use commServicesAccessToken instead of accessToken to match JS-types.
This revision is now accepted and ready to land.Dec 15 2023, 2:54 AM
  1. Refactor to remove deviceID emission.
  2. Rebase before landing.

Have you tested sending events (calling sendAuthMetadataToJS) when there are no listeners? Looking at the code, it should work but I want to make sure it doesn't crash the app

I don't think this got a response

Have you tested sending events (calling sendAuthMetadataToJS) when there are no listeners? Looking at the code, it should work but I want to make sure it doesn't crash the app

I don't think this got a response

I am really sorry for omitting this comment - it wasn't intentional.

I executed test where C++ code kept sending events on each character typed but there were no JS-listeners. Nothing happened.