initial
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.cxx
|
||||
@@ -0,0 +1,70 @@
|
||||
group = "eu.weblibre.pluggable_transports_proxy"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = "2.1.0"
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:8.9.1")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.android.library"
|
||||
apply plugin: "kotlin-android"
|
||||
|
||||
android {
|
||||
namespace = "eu.weblibre.pluggable_transports_proxy"
|
||||
|
||||
compileSdk = 36
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += "src/main/kotlin"
|
||||
test.java.srcDirs += "src/test/kotlin"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||
testImplementation("org.mockito:mockito-core:5.0.0")
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.all {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed", "standardOut", "standardError"
|
||||
outputs.upToDateWhen {false}
|
||||
showStandardStreams = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.netzarchitekten:IPtProxy:4.2.2'
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = 'pluggable_transports_proxy'
|
||||
@@ -0,0 +1,3 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.weblibre.pluggable_transports_proxy">
|
||||
</manifest>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package eu.weblibre.pluggable_transports_proxy
|
||||
|
||||
import IPtProxy.Controller
|
||||
import eu.weblibre.pluggable_transports_proxy.pigeons.IPtProxyController
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.io.File
|
||||
|
||||
/** PluggableTransportsProxyPlugin */
|
||||
class PluggableTransportsProxyPlugin : FlutterPlugin {
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var INSTANCE: Controller? = null
|
||||
|
||||
fun getController(ptDirPath: String): Controller {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
INSTANCE ?: Controller(ptDirPath, true, false, "INFO", null).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
val ptDir = File(flutterPluginBinding.applicationContext.cacheDir, "pt_state")
|
||||
val ptc = getController(ptDir.path)
|
||||
|
||||
IPtProxyController.setUp(flutterPluginBinding.binaryMessenger, ProxyImpl(controller = ptc))
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
// Controller instance remains alive for reuse
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package eu.weblibre.pluggable_transports_proxy
|
||||
|
||||
import eu.weblibre.pluggable_transports_proxy.pigeons.IPtProxyController
|
||||
import eu.weblibre.pluggable_transports_proxy.pigeons.ProxyType
|
||||
|
||||
class ProxyImpl(val controller: IPtProxy.Controller) : IPtProxyController {
|
||||
override fun start(
|
||||
proxyType: ProxyType,
|
||||
proxy: String
|
||||
): Long {
|
||||
val type = when (proxyType) {
|
||||
ProxyType.OBFS4 -> IPtProxy.IPtProxy.Obfs4
|
||||
ProxyType.MEEK_LITE -> IPtProxy.IPtProxy.MeekLite
|
||||
ProxyType.WEBTUNNEL -> IPtProxy.IPtProxy.Webtunnel
|
||||
ProxyType.SNOWFLAKE -> IPtProxy.IPtProxy.Snowflake
|
||||
};
|
||||
|
||||
controller.start(type, proxy)
|
||||
|
||||
return controller.port(type)
|
||||
}
|
||||
|
||||
override fun stop(proxyType: ProxyType) {
|
||||
val type = when (proxyType) {
|
||||
ProxyType.OBFS4 -> IPtProxy.IPtProxy.Obfs4
|
||||
ProxyType.MEEK_LITE -> IPtProxy.IPtProxy.MeekLite
|
||||
ProxyType.WEBTUNNEL -> IPtProxy.IPtProxy.Webtunnel
|
||||
ProxyType.SNOWFLAKE -> IPtProxy.IPtProxy.Snowflake
|
||||
};
|
||||
|
||||
controller.stop(type)
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
// Autogenerated from Pigeon (v26.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
|
||||
|
||||
package eu.weblibre.pluggable_transports_proxy.pigeons
|
||||
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BasicMessageChannel
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MessageCodec
|
||||
import io.flutter.plugin.common.StandardMethodCodec
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
private object ProxyPigeonUtils {
|
||||
|
||||
fun wrapResult(result: Any?): List<Any?> {
|
||||
return listOf(result)
|
||||
}
|
||||
|
||||
fun wrapError(exception: Throwable): List<Any?> {
|
||||
return if (exception is FlutterError) {
|
||||
listOf(
|
||||
exception.code,
|
||||
exception.message,
|
||||
exception.details
|
||||
)
|
||||
} else {
|
||||
listOf(
|
||||
exception.javaClass.simpleName,
|
||||
exception.toString(),
|
||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
||||
* @property code The error code.
|
||||
* @property message The error message.
|
||||
* @property details The error details. Must be a datatype supported by the api codec.
|
||||
*/
|
||||
class FlutterError (
|
||||
val code: String,
|
||||
override val message: String? = null,
|
||||
val details: Any? = null
|
||||
) : Throwable()
|
||||
|
||||
enum class ProxyType(val raw: Int) {
|
||||
OBFS4(0),
|
||||
MEEK_LITE(1),
|
||||
WEBTUNNEL(2),
|
||||
SNOWFLAKE(3);
|
||||
|
||||
companion object {
|
||||
fun ofRaw(raw: Int): ProxyType? {
|
||||
return values().firstOrNull { it.raw == raw }
|
||||
}
|
||||
}
|
||||
}
|
||||
private open class ProxyPigeonCodec : StandardMessageCodec() {
|
||||
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
|
||||
return when (type) {
|
||||
129.toByte() -> {
|
||||
return (readValue(buffer) as Long?)?.let {
|
||||
ProxyType.ofRaw(it.toInt())
|
||||
}
|
||||
}
|
||||
else -> super.readValueOfType(type, buffer)
|
||||
}
|
||||
}
|
||||
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
|
||||
when (value) {
|
||||
is ProxyType -> {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.raw)
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface IPtProxyController {
|
||||
fun start(proxyType: ProxyType, proxy: String): Long
|
||||
fun stop(proxyType: ProxyType)
|
||||
|
||||
companion object {
|
||||
/** The codec used by IPtProxyController. */
|
||||
val codec: MessageCodec<Any?> by lazy {
|
||||
ProxyPigeonCodec()
|
||||
}
|
||||
/** Sets up an instance of `IPtProxyController` to handle messages through the `binaryMessenger`. */
|
||||
@JvmOverloads
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: IPtProxyController?, messageChannelSuffix: String = "") {
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pluggable_transports_proxy.IPtProxyController.start$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val proxyTypeArg = args[0] as ProxyType
|
||||
val proxyArg = args[1] as String
|
||||
val wrapped: List<Any?> = try {
|
||||
listOf(api.start(proxyTypeArg, proxyArg))
|
||||
} catch (exception: Throwable) {
|
||||
ProxyPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pluggable_transports_proxy.IPtProxyController.stop$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val proxyTypeArg = args[0] as ProxyType
|
||||
val wrapped: List<Any?> = try {
|
||||
api.stop(proxyTypeArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
ProxyPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user