Skip to content

Commit

Permalink
feat: implement multithreading
Browse files Browse the repository at this point in the history
  • Loading branch information
anday013 committed Aug 10, 2024
1 parent fd5f7d0 commit c006be9
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 45 deletions.
82 changes: 67 additions & 15 deletions cpp/NativeBcryptCppTurboModule.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,77 @@
#include "NativeBcryptCppTurboModule.h"
//#import <QuartzCore/QuartzCore.h>
#include <thread>

namespace facebook::react
{
NativeBcryptCppTurboModule::NativeBcryptCppTurboModule(std::shared_ptr<CallInvoker> jsinvoker) : NativeBcryptCppCxxSpec<NativeBcryptCppTurboModule>(std::move(jsinvoker)) {}


namespace facebook::react {
NativeBcryptCppTurboModule::NativeBcryptCppTurboModule(std::shared_ptr<CallInvoker> jsinvoker): NativeBcryptCppCxxSpec<NativeBcryptCppTurboModule>(std::move(jsinvoker)) {}

jsi::Value NativeBcryptCppTurboModule::generateHash(jsi::Runtime &rt, std::string password, double workload) {
return jsi::Value::undefined();
jsi::Value NativeBcryptCppTurboModule::generateHash(jsi::Runtime &rt, std::string password, double workload)
{
jsi::Function promiseConstructor = rt.global().getPropertyAsFunction(rt, "Promise");

return promiseConstructor.callAsConstructor(rt,
jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forAscii(rt, "promiseArg"),
2,
[password, workload, jsInvoker = jsInvoker_](
jsi::Runtime &runtime,
const jsi::Value &thisValue,
const jsi::Value *arguments,
std::size_t count) -> jsi::Value
{
auto resolverValue = std::make_shared<jsi::Value>((arguments[0].asObject(runtime)));

std::thread([password, workload, resolverValue = std::move(resolverValue), jsInvoker, &runtime]()
{
std::string hash = bcrypt::generateHash(password, workload);
// Post back to JS thread
jsInvoker->invokeAsync([resolverValue, hash, &runtime]() {
resolverValue->asObject(runtime).asFunction(runtime).call(runtime, hash);
}); })
.detach();
return jsi::Value::undefined();
})

);
}


jsi::Value NativeBcryptCppTurboModule::validatePassword(jsi::Runtime &rt, std::string password, std::string hash) {
return jsi::Value::undefined();
jsi::Value NativeBcryptCppTurboModule::validatePassword(jsi::Runtime &rt, std::string password, std::string hash)
{
jsi::Function promiseConstructor = rt.global().getPropertyAsFunction(rt, "Promise");

return promiseConstructor.callAsConstructor(rt,
jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forAscii(rt, "promiseArg"),
2,
[password, hash, jsInvoker = jsInvoker_](
jsi::Runtime &runtime,
const jsi::Value &thisValue,
const jsi::Value *arguments,
std::size_t count) -> jsi::Value
{
auto resolverValue = std::make_shared<jsi::Value>((arguments[0].asObject(runtime)));

std::thread([password, hash, resolverValue = std::move(resolverValue), jsInvoker, &runtime]()
{
bool isValid = bcrypt::validatePassword(password, hash);
// Post back to JS thread
jsInvoker->invokeAsync([resolverValue, isValid, &runtime]() {
resolverValue->asObject(runtime).asFunction(runtime).call(runtime, isValid);
}); })
.detach();
return jsi::Value::undefined();
})

);
}
std::string NativeBcryptCppTurboModule::generateHashSync(jsi::Runtime &rt, std::string password, double workload){

std::string generatedHash = bcrypt::generateHash(password, workload);
return generatedHash;
std::string NativeBcryptCppTurboModule::generateHashSync(jsi::Runtime &rt, std::string password, double workload)
{
return bcrypt::generateHash(password, workload);
}
bool NativeBcryptCppTurboModule::validatePasswordSync(jsi::Runtime &rt, std::string password, std::string hash) {
bool NativeBcryptCppTurboModule::validatePasswordSync(jsi::Runtime &rt, std::string password, std::string hash)
{
return bcrypt::validatePassword(password, hash);
}

Expand Down
14 changes: 5 additions & 9 deletions example/ios/BcryptCppExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
00E356EE1AD99517003FC87E /* BcryptCppExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BcryptCppExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* BcryptCppExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BcryptCppExampleTests.m; sourceTree = "<group>"; };
0580ABFB39ADC1A50C1EF3C7 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = BcryptCppExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
0580ABFB39ADC1A50C1EF3C7 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = BcryptCppExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* BcryptCppExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BcryptCppExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BcryptCppExample/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = BcryptCppExample/AppDelegate.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -472,6 +472,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 99NF33M5QW;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = BcryptCppExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down Expand Up @@ -499,6 +500,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 99NF33M5QW;
INFOPLIST_FILE = BcryptCppExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -590,10 +592,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -665,10 +664,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
58 changes: 37 additions & 21 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,61 @@ import {
validatePassword,
validatePasswordSync,
} from 'react-native-bcrypt-cpp';
import { MovingRectangle } from './MovingRectangle';

const workload = 15;
const password = 'asdcds-sdjakl12313841skdnanczdeioaj';
const hash = '$2b$15$wX0mKtpwGwzdfbz099nUnu5R.NN/huUK9XBra0sS4xj4XfjfPOkzO';

async function measureTime<T>(fn: () => T): Promise<T> {
const start = performance.now();
const res = await fn();
const end = performance.now();
const timeTaken = end - start;
console.log('Time taken :', timeTaken, 'ms');
return res;
}

export default function App() {
return (
<View style={styles.container}>
<MovingRectangle />
<Button
title="Generate Hash"
onPress={async () => {
const password = 'password';
const workload = 10;
const hash = await generateHash(password, workload);
console.log(hash);
const generatedHash = await measureTime(() =>
generateHash(password, workload)
);
console.log('Generated hash:', generatedHash);
}}
/>
<Button
title="Generate Hash Sync"
onPress={() => console.log(generateHashSync('password', 10))}
title="Validate Password"
onPress={async () => {
const isValid = await measureTime(() =>
validatePassword(password, hash)
);
console.log('isValid', isValid);
}}
/>

<Button
title="Validate Password"
title="Generate Hash Sync"
onPress={async () => {
const password = 'password';
const hash =
'$2a$10$5e1Q8Bj1JWz5J9zQ7H5v3OjL2wz1I0Q9zZ6QzZ1Z1Z1Z1Z1Z1Z1Z1';
const isValid = await validatePassword(password, hash);
console.log(isValid);
const generatedHash = await measureTime(() =>
generateHashSync(password, workload)
);
console.log('Generated hash:', generatedHash);
}}
/>

<Button
title="Validate Password Sync"
onPress={() =>
console.log(
validatePasswordSync(
'password',
'$2a$10$5e1Q8Bj1JWz5J9zQ7H5v3OjL2wz1I0Q9zZ6QzZ1Z1Z1Z1Z1Z1Z1'
)
)
}
onPress={async () => {
const isValid = await measureTime(() =>
validatePasswordSync(password, hash)
);
console.log('isValid', isValid);
}}
/>
</View>
);
Expand Down
51 changes: 51 additions & 0 deletions example/src/MovingRectangle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useEffect, useRef } from 'react';
import { Animated, StyleSheet, View } from 'react-native';

export const MovingRectangle = () => {
const animationValue = useRef(new Animated.Value(0)).current;

useEffect(() => {
const animate = () => {
Animated.loop(
Animated.sequence([
Animated.timing(animationValue, {
toValue: 100,
duration: 300,
useNativeDriver: false, // This runs the animation on the JS thread
}),
Animated.timing(animationValue, {
toValue: 0,
duration: 300,
useNativeDriver: false, // This runs the animation on the JS thread
}),
])
).start();
};

animate();
}, [animationValue]);

return (
<View style={styles.container}>
<Animated.View
style={[
styles.rectangle,
{ transform: [{ translateX: animationValue }] },
]}
/>
</View>
);
};

const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
marginBottom: 50,
},
rectangle: {
width: 100,
height: 100,
backgroundColor: 'blue',
},
});

0 comments on commit c006be9

Please sign in to comment.