How To Integrate Rust Into A React Native App - Varun Dhananjaya - RNL - August 2023

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
my name is Varun I'm based in New York City I work at com Technologies previously I worked at Amazon and I'm a fan of long walks good food and the Arsenal so yeah let's jump into it so at com we have a it feels like endless number of languages that we use we have a react native app and as if that wasn't enough we had to add Java Objective C Swift kotlin C plus plus another question is Russ do we really need one more language so a little bit more background on com is an encrypted messaging app so basically in in the in the and endless number of uh messaging apps today encryption really only works for simple chat it's not really Geared for communities so to do something more complicated requires what we call a key server which is basically a personal application back end that you can use to communicate with the outside world fully antenna encrypted so basically this lets us do things like backup encrypted look ahead encrypted notifications Etc yes you can DM a show my boss if you're interested in trying com so how do we use C plus plus today so we use C plus plus in our react native app for a multitude of reasons some are for encryption so we use Alm which is an implementation of signals double ratchet protocol Brandon encryption we also have a database thread so we run sqlite and this is where we store you know basic user data and stuff like that on the app that we want to persist and then we have networking we use grpc which is not supported on react native's flavor of Js there is a grpc JS library but unfortunately it didn't work for us so we opted initially for a C plus plus grpc framework instead so quick overview you probably since you guys know about react native you've probably heard about the JSI so the JSI is the JavaScript interface and it's just a way to performantly integrate between C plus plus and JavaScript so when stuff happens on the JS thread but we have separate threads for all of the above so let's go over some pros and cons of C plus plus so first pro it has all support there's a shared implementation across IOS and Android you know plenty of react native libraries that are written in C plus plus it's officially supported by Apple Google meta and it's a familiar language I feel like most people aren't maybe in like an intro CS class or maybe an industry have come across C plus plus it's a you know even if there's not always like love for the language there is at least some familiarity there are some cons so the first con is callback hell so when you have so I live in C plus plus 20. this is mitigated a little Maybe 17. where and now there's a single way in C plus plus so it kind of makes this easier and you don't have to write a whole bunch of callbacks but unfortunately in the version of C plus plus that react native ships with as if four months ago anyway when I was researching all of this unfortunately that version of C plus plus did not support async await yet and not to mention that upgrading redact native is such a pain that it's probably not worth it unfit does for most people another con integrating libraries is a big pain as I'll show you our cmake lists and our xcode files are were littered with just random dependencies that we had to pull in just to try to get things to work it felt like developing with C plus plus in our react native app was just constantly fighting against the compiler and the last con that I want to get into is a lack of memory safety so especially with like younger more Junior programmers this can be an issue where you know you might have like a dangling pointer or something like that and it leads to an issue that we can only catch at runtime after you know sifting through a stack Trace and trying to find what what exactly was going on and you know especially with the JSI this is tricky as I'll get into so let's talk about callbacks first so you can see here this is what our C plus plus code looked like roughly six months ago so we have we have this jsr we have a function that's returning a JSI value within that we have a return create promise as a JSI value within that we're invoking something on the crypto thread and then within that we're invoking something on a global DB Singleton and then within that we have to actually call the JSI and the Js invoker to trigger something on our JavaScript thread and you know all this code is it's really tough to wrap your head around there's a lot of nesting and uh yeah some of this can be simplified with like refactoring to reduce the nesting but you don't get away from fact that you're just you got to keep this like massive stack in your head uh and unwind it to figure out what's going on which isn't always very easy then let's go over library integration panes so on Android you have to download a library and build.gradle and then you know there's no there's no standardized package manager for C plus plus so every library has to be manually downloaded and built for each platform similarly on iOS you have to download the library in a pod file then configure the build in xcode and we had to do this for grpc on sqlite Folly boost and it's way more painful than it looks so here's an example of what I'm talking about you can see when we finally pulled out our some of these C plus plus dependencies to replace them with rust how much so yeah that just shows you like the amount of garbage that you actually deal with when integrating a C plus plus Library it's not very fun now the last and probably most important thing is memory safety so I have a question for the audience can anyone here point out what's what's going to cause a seg fault in this code I'll give you a second it's a little tricky because you know a bunch of us also looked at it and it all it took it took actually crashing our apps to figure out the problem all right this is the issue so basically on the database thread we're trying to call the JS runtime and this may or may not lead to a segment it's pretty non-deterministic and it's just no fun to debug so basically long story short C plus plus it's fine we think we can do better so let's talk about JSI and react native with Russ so basically what we've done in our code base and what I'll demonstrate for you today is as thin a layers C plus plus code as possible on the native side of the JSI and then from there we use this cool tool called cxx to generate rust bindings to C plus plus and then from there we can actually write most of our real Logic on the rust side I'm using the Tokyo runtime which is just an async that Russ has in its ecosystem so let's get into it a little more so we talked about these cons right the first one being call back hell so however I saw this Russ has a single weight syntax and with the Tokyo async runtime this is very easy to use there's nothing really that you have to configure you don't have to handle futures manually or anything so the next pain Point integrating libraries rust has rust shifts with cargo which is a package manager but it's also way more than that and it makes managing dependencies really easy it makes compiling a breeze the compile times can be slow with rust that's like one drawback but we found that that is a worthwhile trade-off for us and the last con lack of memory safety well that's maybe Russ claim to famous that it's type safe and memory safe and this is something that every rust developer will be to that but it's worth mentioning or you know endless times because it really is such a lifesaver when you don't have to worry about unless you're writing unsafe Rush which you know is a whole other can of worms you don't have to worry about memory safety which is really nice so let's actually talk about how we can call Russ from C plus plus so and and then you know I'll actually tie that all into our react native app so passing the JS promise to C plus plus is Trivial with JSI but it's a little harder to pass it to rust with cxx this is because you can't pass a reference because Russ borrow Checker doesn't want us to do this therefore we need some way to manage unresolved promises that are waiting for a rest task to complete as you can see here we have a rush promise manager it's been implemented as a Singleton that's responsible for managing promises it keeps a map of promises of Promise IDs to promises you can see that it's called promises here in the code and now we can send the promise ID to Russ And Russ can later send the ID back to C plus plus via a callback at which point we can reject or resolve the corresponding prominence this is what our rust code will call when it's finished with the computation that we've offloaded to it this callback function will either call The Promise manager reject or resolve method depending on what's passed to it so you can see in here we're using poly Dynamic it's just a convenient way to deal with Dynamic types in a statically typed language like C plus plus and now the rust code so note the cxx bridge decorator this is important this tells cxx that this module ffi which stands for foreign function interface is going to serve as the bridge between rust and C plus plus it'll handle generating all the code to get the two to talk to each other within this module we declare which functions will be implemented in Rust within the extern rust block and which will be implemented in C plus plus within the extern C plus plus block so you can see the string callback function is written in C plus plus and we've included it by include with this include Russ callback.h line and similarly we've exposed an add function from Russ that'll be available in C plus plus as rust add so now we have to actually tie it all together this is the last step so now we just have to modify our native turbo module add function to call the rust add function so here's the old code first you can see that we're just resolving a plus b now the new code so it's a little more complicated I'll give you I'll you know I'll give you that but it's not terribly complicated not at least not nearly as bad as the nested C plus plus that I showed earlier so you can see what's going on here is we store the promise with our promise manager and then we pass the promise ID to our rust add function so then when Russ finishes the addition it'll just call the Callback and then the JSI value will be returned to JavaScript I have a brief demo so you can if you're interested in trying it out for yourself here's the link but yeah let me stop screen sharing and pull up the code first and then actually I'll pull up the simulator first demonstrate this and then I think if we have some time I can do some live coding so it's not so Hand wavy so here's the simulator you can basically enter two numbers let's do something that people can add in their head and you can see that it's it works but this isn't really convincing so why don't we jump into the code and try live coding real quick yeah so this is just the front end when we jump into the more interesting stuff though let's go so let's start let's work backwards so let's pull up lib.rs so this is our rest code so right now you can see we have rust add which is just given two numbers in the promised ID and recall that we have to keep this promise ID so that we can eventually resolve or reject it with the Callback which is happening here and then we have like our add function which is spawning an async task and then we have this async ad which actually performs the addition so we could do something I don't know why don't we do we'll call this multiply a helper this way we're not changing too many things oops I have a different form okay well it's just gonna make it ugly formatting apologies multiply and we should so in this so you can see it's complaining now because it's expecting an ad function to be to be defined in Rust and it's not so we just need to change this and we should change the cxx name to the rust multiply now I think that's it now we can go to the C plus plus code we'll call this multiply we'll call this rust multiply again apologies for the formatting and yeah you can see we're doing everything else stays the same all right and we have to update this weird that oh it did right it did find that one okay we should change this to products man as a result we can call it the products or multiply result to keep it consistent all right I think that that might just be it let's try running again oh big failed oops Yeah and so it was complaining that there is still a reference to add in the bridging no that's not the issue oh I think I just need to like clean the build folder all right I think that since I have to clean the build folder this will take like a maybe like a couple minutes it might be worth just opening up to q a and then I can demo or update it out right after okay I think I'm gonna try and give someone a mic to ask a question if you can't hear it I'll just have to repeat it I think the gist was can you I just talked directly to see from through the JSI correct yeah yeah you could do that so actually though I we we tried that it ended up not being a whole lot better the thing is if you think of if you think of you know C C plus plus and rust as the vertices of a triangle it's actually kind of an isosceles triangle where Ceta C plus plus is a pretty long Edge and C plus or and then Cedar rust is also a pretty long Edge but C plus plus to rust is fairly short you know there's not a whole lot that separates them Paradigm wise aside from the borrowed Checker sorry I should take that back there is a lot that separates them but it's not nearly as much as C and rust or C and C plus plus at least that was our experience and so we opted for this approach where you create like a thin C plus plus layer and then try to write the bulk of your logic and rust I'm sure that others have tried it with just C and then yeah you can use there's like t-bind Jet and some other tools that you can use to then call Russ from your C code did you ever consider just doing a crypto and things you're going to do in C plus plus interesting Js was that feasible for your projects like why did you choose not to do that it was it was doable for some things for instance there is a there is an implementation of matrix's own library in in JavaScript or in typescript I think ultimately there are there are a couple things that made native doing it in Native more appealing to us one was that we wouldn't block the Java Script thread for some of these things you know cryptography a lot of the operations can be pretty expensive and so it we saw the app's performance deteriorate significantly when we tried to implement some of the crypto stuff and the JS thread so moving it to its own native thread uh made a lot of sense for us it's it's significantly improved the performance of the app okay I think that's all for questions for you are you going to go ahead with your demo now or let me see what's going on one second I thought I would have completed by now but let me share my slides again you can grab the link to the repo and try it out for yourself so this is the link to the repo you you have to when you do the Pod install you have to use the Newark you are just at like a new architecture flag but that's pretty easy to see in the Pod file and then if you want to connect here's my GitHub and my Twitter or X I should say all right yeah thanks for having me you know it's been it's been a pleasure and really enjoyed the talks before so keep it up and I look forward to seeing what you guys do in the future nice thanks [Applause]
Info
Channel: Pusher
Views: 896
Rating: undefined out of 5
Keywords: developer language, language code, libraries, help, tips, forum, meet-up, meet up, learn code, coding education, coding hints and tips, lecture, coding lecture, learn about code, learn a developer language, amazon alexa skills, developer conference, node.js, javascript, backend
Id: 6yRJjYR3urE
Channel Id: undefined
Length: 23min 3sec (1383 seconds)
Published: Thu Sep 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.