Skip to content

Commit

Permalink
Merge pull request #44 from Sifir-io/feat/rn65_timeout
Browse files Browse the repository at this point in the history
feat: [example] add rn67 example and refactor kotlin
  • Loading branch information
gabidi authored Feb 8, 2022
2 parents f1ebefd + 07affca commit ed9dc6f
Show file tree
Hide file tree
Showing 66 changed files with 30,771 additions and 9,984 deletions.
4 changes: 2 additions & 2 deletions android/src/main/java/com/reactnativetor/TcpStreamStart.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import com.sifir.tor.TorServiceParam
class TcpStreamStart constructor(
private val target: String,
private val proxy:String,
private val timeoutMs:Long,
private val timeoutMs:Double,
private val onSuccess: (stream: TcpSocksStream) -> Unit,
private val onError: (e: Throwable) -> Unit
) {
fun run() {
try {
val stream = TcpSocksStream(target,proxy,timeoutMs);
val stream = TcpSocksStream(target,proxy,timeoutMs.toLong());
onSuccess(stream);
} catch (e: Error) {
Log.d("TorBridge:TcpStream", "error $e")
Expand Down
27 changes: 15 additions & 12 deletions android/src/main/java/com/reactnativetor/TorBridgeRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.util.Base64
import android.util.Log
import com.facebook.react.bridge.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.io.IOException

Expand All @@ -27,7 +29,7 @@ class TorBridgeRequest constructor(
protected val param: TaskParam
) {

protected fun onPostExecute(result: RequestResult?){
protected fun onPostExecute(result: RequestResult?) {
when (result) {
is RequestResult.Error -> {
if (result.error !== null) {
Expand All @@ -37,7 +39,10 @@ class TorBridgeRequest constructor(
}
}
is RequestResult.Success -> mPromise!!.resolve(result.result)
else -> mPromise!!.reject("Unable to process RequestResult: Exhaustive Clause")
else -> mPromise!!.reject(
"Unable to process RequestResult",
"RequestResult Exhaustive Clause"
)
}
mPromise = null
}
Expand All @@ -47,15 +52,13 @@ class TorBridgeRequest constructor(
val request = when (param.method.toUpperCase()) {
"POST" -> {
// Check Content-Type headers provided
// Currently only support application/x-www-form-urlencoded
// Currently only supports application/x-www-form-urlencoded
// If not provided defaults to application/json
// TODO Expand supported content formats ?
val body = when (param.headers?.get("Content-Type") ?: "application/json") {
"application/x-www-form-urlencoded" -> FormBody.create(
MediaType.get("application/x-www-form-urlencoded; charset=utf-8"),
param.json!!
)
else -> RequestBody.create(MediaType.get("application/json; charset=utf-8"), param.json!!)
"application/x-www-form-urlencoded" ->
param.json!!.toRequestBody("application/x-www-form-urlencoded; charset=utf-8".toMediaType())
else -> param.json!!.toRequestBody("application/json; charset=utf-8".toMediaType())
}
Request.Builder().url(param.url)
.post(body)
Expand All @@ -76,16 +79,16 @@ class TorBridgeRequest constructor(
val resp = Arguments.createMap()
val headersMap = Arguments.createMap()

response.headers().toMultimap().map {
response.headers.toMultimap().map {
headersMap.putArray(it.key.toString(), Arguments.fromList(it.value))
}
resp.putMap("headers", headersMap)

val respCode = response.code()
val respCode = response.code
resp.putInt("respCode", respCode)

val contentType = response.header("content-type").toString();
val body = response.body()?.bytes()
val body = response.body?.bytes()
if (contentType is String) {
resp.putString("mimeType", contentType)
if (contentType.startsWith("application/json") || contentType.startsWith("application/javascript")) {
Expand All @@ -96,7 +99,7 @@ class TorBridgeRequest constructor(
}
resp.putString("b64Data", Base64.encodeToString(body, Base64.DEFAULT))

if (response.code() > 299) {
if (response.code > 299) {
onPostExecute(
RequestResult.Error(
"Request Response Code ($respCode)",
Expand Down
63 changes: 45 additions & 18 deletions android/src/main/java/com/reactnativetor/TorModule.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.reactnativetor

import android.content.Context
import android.util.Log
import com.facebook.react.bridge.*
import com.sifir.tor.DataObserver
Expand All @@ -11,12 +12,11 @@ import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Proxy;
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import org.json.JSONObject
import java.util.UUID;
import java.util.concurrent.*
import javax.net.ssl.*


/**
Expand Down Expand Up @@ -52,13 +52,17 @@ class DataObserverEmitter(
}
}


class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
private var _client: OkHttpClient? = null;
private var service: OwnedTorService? = null;
private var proxy: Proxy? = null;
private var _starting: Boolean = false;
private var _streams: HashMap<String, TcpSocksStream> = HashMap();
// private val executorService: ExecutorService = Executors.newFixedThreadPool(4)
private val executorService : ThreadPoolExecutor = ThreadPoolExecutor(4,4, 0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue<Runnable>());

// private val executorService: ExecutorService = Executors.newFixedThreadPool(4)
private val executorService: ThreadPoolExecutor =
ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue<Runnable>(50));


/**
Expand Down Expand Up @@ -87,7 +91,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod

return OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
.hostnameVerifier(HostnameVerifier { _: String, _: SSLSession -> true })
}

override fun getName(): String {
Expand Down Expand Up @@ -124,24 +128,33 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
method: String,
jsonBody: String,
headers: ReadableMap,
// FIXME move this to startDeamon call
trustAllSSl: Boolean,
promise: Promise
) {
if (service == null) {
promise.reject(Throwable("Service Not Initialized!, Call startDaemon first"));
return;
}

var client = (if (trustAllSSl) getUnsafeOkHttpClient() else OkHttpClient().newBuilder())
.proxy(proxy)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build()
// if(_client !is OkHttpClient){
// _client = (if (trustAllSSl) getUnsafeOkHttpClient() else OkHttpClient().newBuilder())
// .proxy(proxy)
// .connectTimeout(10, TimeUnit.SECONDS)
// .writeTimeout(10, TimeUnit.SECONDS)
// .readTimeout(10, TimeUnit.SECONDS)
// .build()
// }

if(_client !is OkHttpClient){
promise.reject(Throwable("Request http client not Initialized!, Call startDaemon first"));
return;
}

val param = TaskParam(method, url, jsonBody, headers.toHashMap())
executorService.execute {
try {
val task = TorBridgeRequest(promise, client, param);
val task = TorBridgeRequest(promise, _client!!, param);
task.run()
} catch (e: Exception) {
Log.d("TorBridge", "error on request: $e")
Expand All @@ -152,27 +165,38 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod


@ReactMethod
fun startDaemon(timeoutMs: Double, promise: Promise) {
fun startDaemon(timeoutMs: Double, clientTimeoutSeconds: Double, promise: Promise) {
Log.d("TorBridge", "->startDaemon")
if (service != null) {
promise.reject(Throwable("Service already running, call stopDaemon first"))
return;
}
if (this._starting) {
promise.reject(Throwable("Service already starting"))
return;
}
_starting = true;
executorService.execute {
val socksPort = findFreePort();
val path = this.reactApplicationContext.cacheDir.toString();
val param = StartParam(socksPort, path, timeoutMs.toLong())
val param = StartParam(socksPort, path, timeoutMs)
try {
TorBridgeStartAsync(param, {
service = it
proxy = Proxy(Proxy.Type.SOCKS, InetSocketAddress("0.0.0.0", socksPort))
_starting = false;

_client = getUnsafeOkHttpClient()
.proxy(proxy)
.connectTimeout(clientTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.writeTimeout(clientTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.readTimeout(clientTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.build();

promise.resolve(socksPort);
}, {
_starting = false;
promise.reject(it);
promise.reject("StartDaemon Error", "Error starting Tor Daemon", it);
}).run();

} catch (e: Exception) {
Expand Down Expand Up @@ -217,7 +241,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
if (service == null) {
throw Exception("Tor service not running, call startDaemon first")
}
TcpStreamStart(target, "0.0.0.0:${service?.socksPort}", timeoutMs.toLong(), {
TcpStreamStart(target, "0.0.0.0:${service?.socksPort}", timeoutMs, {
// Assign UUID to connection to manage it
val uuid = UUID.randomUUID();
val connId = uuid.toString();
Expand All @@ -243,7 +267,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
throw Throwable("Tor Service not running, call startDaemon first")
}
var stream = _streams[connId]
?: throw Throwable("Stream for connectionId $connId is not initialized, call startTcpConn first");
?: throw Throwable("Stream for connectionId $connId is not initialized, call startTcpConn first");
stream.send_data(msg, timeoutSec.toLong());
promise.resolve(true);
} catch (e: Exception) {
Expand All @@ -265,4 +289,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
promise.reject(e)
}
}

}


3 changes: 2 additions & 1 deletion android/src/main/java/com/reactnativetor/TorPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class TorPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
val manager = reactContext.getPackageManager();
val ai = manager.getApplicationInfo(reactContext.packageName, PackageManager.GET_META_DATA);
System.load("${ai.nativeLibraryDir}/libsifir_android.so");
System.loadLibrary("sifir_android")
// System.load("${ai.nativeLibraryDir}/libsifir_android.so");
return Arrays.asList<NativeModule>(TorModule(reactContext))
}

Expand Down
4 changes: 2 additions & 2 deletions android/src/main/java/com/reactnativetor/TorStartAsync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.sifir.tor.TorServiceParam
class StartParam(
val socksPort: Int,
var path: String,
val timeoutMs: Long
val timeoutMs: Double
);

class TorBridgeStartAsync constructor(
Expand All @@ -21,7 +21,7 @@ class TorBridgeStartAsync constructor(
fun run() {
try {
Log.d("TorBridge", "Starting Tor with ${param.path} ${param.socksPort} ${param.timeoutMs}")
val ownedTor = OwnedTorService(TorServiceParam(param.path, param.socksPort,param.timeoutMs));
val ownedTor = OwnedTorService(TorServiceParam(param.path, param.socksPort,param.timeoutMs.toLong()));
onSuccess(ownedTor);
} catch (e: Exception) {
Log.d("TorBridge:StartAsync", "error onPostExecute$e")
Expand Down
6 changes: 6 additions & 0 deletions example_rn66/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
16 changes: 16 additions & 0 deletions example_rn66/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
root: true,
extends: '@react-native-community',
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
overrides: [
{
files: ['*.ts', '*.tsx'],
rules: {
'@typescript-eslint/no-shadow': ['error'],
'no-shadow': 'off',
'no-undef': 'off',
},
},
],
};
60 changes: 60 additions & 0 deletions example_rn66/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/
7 changes: 7 additions & 0 deletions example_rn66/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
};
1 change: 1 addition & 0 deletions example_rn66/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Loading

0 comments on commit ed9dc6f

Please sign in to comment.