Compare commits

..

14 Commits

Author SHA1 Message Date
2dust 28639cc388 Merge pull request #468 from yuhan6665/cleanup-config
Remove legacy "connectionReuse" in config
2020-07-18 14:01:38 +08:00
2dust ca254b2aa1 Merge pull request #443 from yuhan6665/resume-speed
Fix speed display after screen turns on
2020-07-18 14:00:48 +08:00
2dust 9721879713 Merge pull request #432 from yuhan6665/drawer-ui
fix highlight issue in drawer ui
2020-07-18 13:59:47 +08:00
2dust 623c1807c5 Merge pull request #409 from yuhan6665/test-cleanup
Tcp test cleanup
2020-07-18 13:58:37 +08:00
2dust 739fa88ba7 Merge pull request #335 from yuhan6665/sub-index
Fix selected index when update subscription
2020-07-18 13:58:11 +08:00
2dust 85d6f00f8c Merge pull request #474 from yuhan6665/dns-cache-timeout
Refresh prepared domain every 30 minutes
2020-07-18 09:48:16 +08:00
yuhan6665 8986710453 Cancel async block when user test tcping again
Change async code to use Kotlin coroutine instead of Anko,
since Anko is deprecated and coroutine is the recommanded
approach now.
2020-07-16 19:42:43 -04:00
yuhan6665 f54faacbf6 Close connecting sockets when user test tcping again 2020-07-16 19:42:43 -04:00
yuhan6665 903352ec9c Refresh prepared domain every 30 minutes 2020-06-19 23:42:02 -04:00
yuhan6665 ad56106c08 Remove legacy "connectionReuse" in config
Also auto-refactor the data class naming to be proper camelcase
2020-06-13 23:38:33 -04:00
yuhan6665 aea8369b8a Fix speed display after screen turns on
Also, use the tab to make the text less jumpy
2020-05-29 22:54:55 -04:00
yuhan6665 92d2cb35c4 Make drawer item unchecked
Current checked item is not consistent with the active activity.
In fact, we don't need checked state. This is a standard behavior.
You can find in apps like Google Playstore.
2020-05-24 11:13:12 -04:00
yuhan6665 6ce3d540e8 Remove config item in drawer
The drawer is attached to MainActivity. When user see the drawer, the
MainActivity must be active. Showing an menu item to launch itself is
confusing.
2020-05-24 11:09:11 -04:00
yuhan6665 8b149fb52f Fix selected index when update subscription 2020-04-03 18:58:41 -04:00
12 changed files with 135 additions and 79 deletions
+10 -5
View File
@@ -24,6 +24,7 @@ type resolved struct {
domain string domain string
IPs []net.IP IPs []net.IP
Port int Port int
lastResolved time.Time
ipIdx uint8 ipIdx uint8
ipLock sync.Mutex ipLock sync.Mutex
lastSwitched time.Time lastSwitched time.Time
@@ -97,7 +98,7 @@ func (d *ProtectedDialer) PrepareResolveChan() {
d.resolveChan = make(chan struct{}) d.resolveChan = make(chan struct{})
} }
func (d *ProtectedDialer) ResolveChan() <-chan struct{} { func (d *ProtectedDialer) ResolveChan() chan struct{} {
return d.resolveChan return d.resolveChan
} }
@@ -137,9 +138,10 @@ func (d *ProtectedDialer) lookupAddr(addr string) (*resolved, error) {
} }
rs := &resolved{ rs := &resolved{
domain: host, domain: host,
IPs: IPs, IPs: IPs,
Port: portnum, Port: portnum,
lastResolved: time.Now(),
} }
return rs, nil return rs, nil
@@ -150,7 +152,6 @@ func (d *ProtectedDialer) PrepareDomain(domainName string, closeCh <-chan struct
log.Printf("Preparing Domain: %s", domainName) log.Printf("Preparing Domain: %s", domainName)
d.currentServer = domainName d.currentServer = domainName
defer close(d.resolveChan)
maxRetry := 10 maxRetry := 10
for { for {
if maxRetry == 0 { if maxRetry == 0 {
@@ -212,6 +213,10 @@ func (d *ProtectedDialer) Dial(ctx context.Context,
} }
} }
if time.Now().Sub(d.vServer.lastResolved) > time.Minute * 30 {
d.PrepareDomain(Address, nil)
}
fd, err := d.getFd(dest.Network) fd, err := d.getFd(dest.Network)
if err != nil { if err != nil {
return nil, err return nil, err
+4 -1
View File
@@ -71,7 +71,10 @@ func (v *V2RayPoint) RunLoop() (err error) {
if !v.status.IsRunning { if !v.status.IsRunning {
v.closeChan = make(chan struct{}) v.closeChan = make(chan struct{})
v.dialer.PrepareResolveChan() v.dialer.PrepareResolveChan()
go v.dialer.PrepareDomain(v.DomainName, v.closeChan) go func() {
v.dialer.PrepareDomain(v.DomainName, v.closeChan)
close(v.dialer.ResolveChan())
}()
go func() { go func() {
select { select {
// wait until resolved // wait until resolved
+4
View File
@@ -84,6 +84,10 @@ dependencies {
implementation project(':dpreference') implementation project(':dpreference')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.2" // 1.3.x has compile error:
// More than one file was found with OS independent path 'META-INF/proguard/coroutines.pro'
// Android support library // Android support library
implementation "com.android.support:support-v4:$supportLibVersion" implementation "com.android.support:support-v4:$supportLibVersion"
implementation "com.android.support:appcompat-v7:$supportLibVersion" implementation "com.android.support:appcompat-v7:$supportLibVersion"
@@ -64,22 +64,21 @@ data class V2rayConfig(
data class StreamSettingsBean(var network: String, data class StreamSettingsBean(var network: String,
var security: String, var security: String,
var tcpSettings: TcpsettingsBean?, var tcpSettings: TcpSettingsBean?,
var kcpsettings: KcpsettingsBean?, var kcpSettings: KcpSettingsBean?,
var wssettings: WssettingsBean?, var wsSettings: WsSettingsBean?,
var httpsettings: HttpsettingsBean?, var httpSettings: HttpSettingsBean?,
var tlssettings: TlssettingsBean?, var tlsSettings: TlsSettingsBean?,
var quicsettings: QuicsettingBean? var quicSettings: QuicSettingBean?
) { ) {
data class TcpsettingsBean(var connectionReuse: Boolean = true, data class TcpSettingsBean(var header: HeaderBean = HeaderBean()) {
var header: HeaderBean = HeaderBean()) {
data class HeaderBean(var type: String = "none", data class HeaderBean(var type: String = "none",
var request: Any? = null, var request: Any? = null,
var response: Any? = null) var response: Any? = null)
} }
data class KcpsettingsBean(var mtu: Int = 1350, data class KcpSettingsBean(var mtu: Int = 1350,
var tti: Int = 20, var tti: Int = 20,
var uplinkCapacity: Int = 12, var uplinkCapacity: Int = 12,
var downlinkCapacity: Int = 100, var downlinkCapacity: Int = 100,
@@ -90,20 +89,20 @@ data class V2rayConfig(
data class HeaderBean(var type: String = "none") data class HeaderBean(var type: String = "none")
} }
data class WssettingsBean(var connectionReuse: Boolean = true, data class WsSettingsBean(var path: String = "",
var path: String = "",
var headers: HeadersBean = HeadersBean()) { var headers: HeadersBean = HeadersBean()) {
data class HeadersBean(var Host: String = "") data class HeadersBean(var Host: String = "")
} }
data class HttpsettingsBean(var host: List<String> = ArrayList<String>(), var path: String = "") data class HttpSettingsBean(var host: List<String> = ArrayList(),
var path: String = "")
data class TlssettingsBean(var allowInsecure: Boolean = true, data class TlsSettingsBean(var allowInsecure: Boolean = true,
var serverName: String = "") var serverName: String = "")
data class QuicsettingBean(var security: String = "none", data class QuicSettingBean(var security: String = "none",
var key: String = "", var key: String = "",
var header: HeaderBean = HeaderBean()) { var header: HeaderBean = HeaderBean()) {
data class HeaderBean(var type: String = "none") data class HeaderBean(var type: String = "none")
} }
} }
@@ -27,34 +27,37 @@ const val divisor = 1024F
fun Long.toSpeedString() = toTrafficString() + "/s" fun Long.toSpeedString() = toTrafficString() + "/s"
fun Long.toTrafficString(): String { fun Long.toTrafficString(): String {
if (this == 0L)
return "\t\t\t0\t B"
if (this < threshold) if (this < threshold)
return "$this B" return "${this.toFloat().toShortString()}\t B"
val kib = this / divisor val kib = this / divisor
if (kib < threshold) if (kib < threshold)
return "${kib.toShortString()} KB" return "${kib.toShortString()}\t KB"
val mib = kib / divisor val mib = kib / divisor
if (mib < threshold) if (mib < threshold)
return "${mib.toShortString()} MB" return "${mib.toShortString()}\t MB"
val gib = mib / divisor val gib = mib / divisor
if (gib < threshold) if (gib < threshold)
return "${gib.toShortString()} GB" return "${gib.toShortString()}\t GB"
val tib = gib / divisor val tib = gib / divisor
if (tib < threshold) if (tib < threshold)
return "${tib.toShortString()} TB" return "${tib.toShortString()}\t TB"
val pib = tib / divisor val pib = tib / divisor
if (pib < threshold) if (pib < threshold)
return "${pib.toShortString()} PB" return "${pib.toShortString()}\t PB"
return "∞" return "∞"
} }
private fun Float.toShortString(): String { private fun Float.toShortString(): String {
val s = toString() val s = "%.2f".format(this)
if (s.length <= 4) if (s.length <= 4)
return s return s
return s.substring(0, 4).removeSuffix(".") return s.substring(0, 4).removeSuffix(".")
@@ -52,6 +52,7 @@ class V2RayVpnService : VpnService() {
} }
private val v2rayPoint = Libv2ray.newV2RayPoint(V2RayCallback()) private val v2rayPoint = Libv2ray.newV2RayPoint(V2RayCallback())
private var lastQueryTime = 0L
private lateinit var configContent: String private lateinit var configContent: String
private lateinit var mInterface: ParcelFileDescriptor private lateinit var mInterface: ParcelFileDescriptor
val fd: Int get() = mInterface.fd val fd: Int get() = mInterface.fd
@@ -182,6 +183,7 @@ class V2RayVpnService : VpnService() {
// Create a new interface using the builder and save the parameters. // Create a new interface using the builder and save the parameters.
mInterface = builder.establish() mInterface = builder.establish()
sendFd() sendFd()
lastQueryTime = System.currentTimeMillis()
startSpeedNotification() startSpeedNotification()
} }
@@ -383,10 +385,13 @@ class V2RayVpnService : VpnService() {
val uplink = v2rayPoint.queryStats("socks", "uplink") val uplink = v2rayPoint.queryStats("socks", "uplink")
val downlink = v2rayPoint.queryStats("socks", "downlink") val downlink = v2rayPoint.queryStats("socks", "downlink")
val zero_speed = (uplink == 0L && downlink == 0L) val zero_speed = (uplink == 0L && downlink == 0L)
val queryTime = System.currentTimeMillis()
if (!zero_speed || !last_zero_speed) { if (!zero_speed || !last_zero_speed) {
updateNotification("${cf_name} • ${(uplink / 3).toSpeedString()}↑ ${(downlink / 3).toSpeedString()}↓") updateNotification("${cf_name} • ${(uplink * 1000 / (queryTime - lastQueryTime)).toSpeedString()}↑" +
" ${(downlink * 1000 / (queryTime - lastQueryTime)).toSpeedString()}↓")
} }
last_zero_speed = zero_speed last_zero_speed = zero_speed
lastQueryTime = queryTime
} }
} }
} }
@@ -55,7 +55,6 @@ abstract class BaseDrawerActivity : BaseActivity() {
this@BaseDrawerActivity, R.anim.fade_in, R.anim.fade_out).toBundle() this@BaseDrawerActivity, R.anim.fade_in, R.anim.fade_out).toBundle()
var activityClass: Class<*>? = null var activityClass: Class<*>? = null
when (mItemToOpenWhenDrawerCloses) { when (mItemToOpenWhenDrawerCloses) {
R.id.server_profile -> activityClass = MainActivity::class.java
R.id.sub_setting -> activityClass = SubSettingActivity::class.java R.id.sub_setting -> activityClass = SubSettingActivity::class.java
R.id.settings -> activityClass = SettingsActivity::class.java R.id.settings -> activityClass = SettingsActivity::class.java
R.id.logcat -> { R.id.logcat -> {
@@ -195,9 +194,7 @@ abstract class BaseDrawerActivity : BaseActivity() {
true true
} }
if (MainActivity::class.java.isAssignableFrom(javaClass)) { if (SubSettingActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.server_profile)
} else if (SubSettingActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.sub_setting) navigationView.setCheckedItem(R.id.sub_setting)
} else if (SettingsActivity::class.java.isAssignableFrom(javaClass)) { } else if (SettingsActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.settings) navigationView.setCheckedItem(R.id.settings)
@@ -33,6 +33,7 @@ import rx.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.util.AngConfigManager.configs import com.v2ray.ang.util.AngConfigManager.configs
import kotlinx.coroutines.*
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener { class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
companion object { companion object {
@@ -58,6 +59,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
private val adapter by lazy { MainRecyclerAdapter(this) } private val adapter by lazy { MainRecyclerAdapter(this) }
private var mItemTouchHelper: ItemTouchHelper? = null private var mItemTouchHelper: ItemTouchHelper? = null
private val testingJobs = ArrayList<Job>()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -240,18 +242,25 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
} }
R.id.ping_all -> { R.id.ping_all -> {
testingJobs.forEach {
it.cancel()
}
testingJobs.clear()
Utils.closeAllTcpSockets()
for (k in 0 until configs.vmess.count()) { for (k in 0 until configs.vmess.count()) {
configs.vmess[k].testResult = "" configs.vmess[k].testResult = ""
adapter.updateConfigList() adapter.updateConfigList()
} }
for (k in 0 until configs.vmess.count()) { for (k in 0 until configs.vmess.count()) {
if (configs.vmess[k].configType != AppConfig.EConfigType.Custom) { if (configs.vmess[k].configType != AppConfig.EConfigType.Custom) {
doAsync { testingJobs.add(GlobalScope.launch(Dispatchers.IO) {
configs.vmess[k].testResult = Utils.tcping(configs.vmess[k].address, configs.vmess[k].port) configs.vmess[k].testResult = Utils.tcping(configs.vmess[k].address, configs.vmess[k].port)
uiThread { val myJob = coroutineContext[Job]
launch(Dispatchers.Main) {
testingJobs.remove(myJob)
adapter.updateSelectedItem(k) adapter.updateSelectedItem(k)
} }
} })
} }
} }
true true
@@ -570,4 +579,4 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
drawer_layout.closeDrawer(GravityCompat.START) drawer_layout.closeDrawer(GravityCompat.START)
return true return true
} }
} }
@@ -104,16 +104,7 @@ object AngConfigManager {
angConfig.vmess.removeAt(index) angConfig.vmess.removeAt(index)
//移除的是活动的 //移除的是活动的
if (angConfig.index == index) { adjustIndexForRemovalAt(index)
if (angConfig.vmess.count() > 0) {
angConfig.index = 0
} else {
angConfig.index = -1
}
} else if (index < angConfig.index)//移除活动之前的
{
angConfig.index--
}
storeConfigFile() storeConfigFile()
} catch (e: Exception) { } catch (e: Exception) {
@@ -123,6 +114,19 @@ object AngConfigManager {
return 0 return 0
} }
private fun adjustIndexForRemovalAt(index: Int) {
if (angConfig.index == index) {
if (angConfig.vmess.count() > 0) {
angConfig.index = 0
} else {
angConfig.index = -1
}
} else if (index < angConfig.index)//移除活动之前的
{
angConfig.index--
}
}
fun swapServer(fromPosition: Int, toPosition: Int): Int { fun swapServer(fromPosition: Int, toPosition: Int): Int {
try { try {
Collections.swap(angConfig.vmess, fromPosition, toPosition) Collections.swap(angConfig.vmess, fromPosition, toPosition)
@@ -241,7 +245,7 @@ object AngConfigManager {
/** /**
* import config form qrcode or... * import config form qrcode or...
*/ */
fun importConfig(server: String?, subid: String): Int { fun importConfig(server: String?, subid: String, removedSelectedServer: AngConfig.VmessBean?): Int {
try { try {
if (server == null || TextUtils.isEmpty(server)) { if (server == null || TextUtils.isEmpty(server)) {
return R.string.toast_none_data return R.string.toast_none_data
@@ -361,6 +365,12 @@ object AngConfigManager {
} else { } else {
return R.string.toast_incorrect_protocol return R.string.toast_incorrect_protocol
} }
if (removedSelectedServer != null &&
vmess.subid.equals(removedSelectedServer.subid) &&
vmess.address.equals(removedSelectedServer.address) &&
vmess.port.equals(removedSelectedServer.port)) {
setActiveServer(configs.vmess.count() - 1)
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
return -1 return -1
@@ -728,6 +738,11 @@ object AngConfigManager {
if (servers == null) { if (servers == null) {
return 0 return 0
} }
val removedSelectedServer =
if (!TextUtils.isEmpty(subid) && configs.vmess[configs.index].subid.equals(subid))
configs.vmess[configs.index]
else
null
removeServerViaSubid(subid) removeServerViaSubid(subid)
// var servers = server // var servers = server
@@ -738,7 +753,7 @@ object AngConfigManager {
var count = 0 var count = 0
servers.lines() servers.lines()
.forEach { .forEach {
val resId = importConfig(it, subid) val resId = importConfig(it, subid, removedSelectedServer)
if (resId == 0) { if (resId == 0) {
count++ count++
} }
@@ -778,6 +793,7 @@ object AngConfigManager {
for (k in configs.vmess.count() - 1 downTo 0) { for (k in configs.vmess.count() - 1 downTo 0) {
if (configs.vmess[k].subid.equals(subid)) { if (configs.vmess[k].subid.equals(subid)) {
angConfig.vmess.removeAt(k) angConfig.vmess.removeAt(k)
adjustIndexForRemovalAt(k)
} }
} }
@@ -31,6 +31,7 @@ import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.service.V2RayVpnService import com.v2ray.ang.service.V2RayVpnService
import com.v2ray.ang.ui.SettingsActivity import com.v2ray.ang.ui.SettingsActivity
import kotlinx.android.synthetic.main.activity_logcat.* import kotlinx.android.synthetic.main.activity_logcat.*
import kotlinx.coroutines.isActive
import me.dozen.dpreference.DPreference import me.dozen.dpreference.DPreference
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
import org.jetbrains.anko.uiThread import org.jetbrains.anko.uiThread
@@ -44,10 +45,13 @@ import java.util.regex.Pattern
import java.math.BigInteger import java.math.BigInteger
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import libv2ray.Libv2ray import libv2ray.Libv2ray
import kotlin.coroutines.coroutineContext
object Utils { object Utils {
val tcpTestingSockets = ArrayList<Socket?>()
/** /**
* convert string to editalbe for kotlin * convert string to editalbe for kotlin
* *
@@ -483,10 +487,13 @@ object Utils {
/** /**
* tcping * tcping
*/ */
fun tcping(url: String, port: Int): String { suspend fun tcping(url: String, port: Int): String {
var time = -1L var time = -1L
for (k in 0 until 2) { for (k in 0 until 2) {
val one = socketConnectTime(url, port) val one = socketConnectTime(url, port)
if (!coroutineContext.isActive) {
break
}
if (one != -1L ) if (one != -1L )
if(time == -1L || one < time) { if(time == -1L || one < time) {
time = one time = one
@@ -497,19 +504,35 @@ object Utils {
fun socketConnectTime(url: String, port: Int): Long { fun socketConnectTime(url: String, port: Int): Long {
try { try {
val socket = Socket()
synchronized(this) {
tcpTestingSockets.add(socket)
}
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val socket = Socket(url, port) socket.connect(InetSocketAddress(url, port))
val time = System.currentTimeMillis() - start val time = System.currentTimeMillis() - start
synchronized(this) {
tcpTestingSockets.remove(socket)
}
socket.close() socket.close()
return time return time
} catch (e: UnknownHostException) { } catch (e: UnknownHostException) {
e.printStackTrace() e.printStackTrace()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() Log.d(AppConfig.ANG_PACKAGE, "socketConnectTime IOException: $e")
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
return -1 return -1
} }
fun closeAllTcpSockets() {
synchronized(this) {
tcpTestingSockets.forEach {
it?.close()
}
tcpTestingSockets.clear()
}
}
} }
@@ -9,7 +9,6 @@ import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.AngConfig.VmessBean import com.v2ray.ang.dto.AngConfig.VmessBean
import com.v2ray.ang.dto.V2rayConfig import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.ui.SettingsActivity import com.v2ray.ang.ui.SettingsActivity
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@@ -246,7 +245,7 @@ object V2rayConfigUtil {
//streamSettings //streamSettings
when (streamSettings.network) { when (streamSettings.network) {
"kcp" -> { "kcp" -> {
val kcpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean() val kcpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.KcpSettingsBean()
kcpsettings.mtu = 1350 kcpsettings.mtu = 1350
kcpsettings.tti = 50 kcpsettings.tti = 50
kcpsettings.uplinkCapacity = 12 kcpsettings.uplinkCapacity = 12
@@ -254,34 +253,33 @@ object V2rayConfigUtil {
kcpsettings.congestion = false kcpsettings.congestion = false
kcpsettings.readBufferSize = 1 kcpsettings.readBufferSize = 1
kcpsettings.writeBufferSize = 1 kcpsettings.writeBufferSize = 1
kcpsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean.HeaderBean() kcpsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.KcpSettingsBean.HeaderBean()
kcpsettings.header.type = vmess.headerType kcpsettings.header.type = vmess.headerType
streamSettings.kcpsettings = kcpsettings streamSettings.kcpSettings = kcpsettings
} }
"ws" -> { "ws" -> {
val wssettings = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean() val wssettings = V2rayConfig.OutboundBean.StreamSettingsBean.WsSettingsBean()
wssettings.connectionReuse = true
val host = vmess.requestHost.trim() val host = vmess.requestHost.trim()
val path = vmess.path.trim() val path = vmess.path.trim()
if (!TextUtils.isEmpty(host)) { if (!TextUtils.isEmpty(host)) {
wssettings.headers = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean.HeadersBean() wssettings.headers = V2rayConfig.OutboundBean.StreamSettingsBean.WsSettingsBean.HeadersBean()
wssettings.headers.Host = host wssettings.headers.Host = host
} }
if (!TextUtils.isEmpty(path)) { if (!TextUtils.isEmpty(path)) {
wssettings.path = path wssettings.path = path
} }
streamSettings.wssettings = wssettings streamSettings.wsSettings = wssettings
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlssettingsBean() val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlsSettingsBean()
tlssettings.allowInsecure = true tlssettings.allowInsecure = true
if (!TextUtils.isEmpty(host)) { if (!TextUtils.isEmpty(host)) {
tlssettings.serverName = host tlssettings.serverName = host
} }
streamSettings.tlssettings = tlssettings streamSettings.tlsSettings = tlssettings
} }
"h2" -> { "h2" -> {
val httpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.HttpsettingsBean() val httpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.HttpSettingsBean()
val host = vmess.requestHost.trim() val host = vmess.requestHost.trim()
val path = vmess.path.trim() val path = vmess.path.trim()
@@ -289,31 +287,30 @@ object V2rayConfigUtil {
httpsettings.host = host.split(",").map { it.trim() } httpsettings.host = host.split(",").map { it.trim() }
} }
httpsettings.path = path httpsettings.path = path
streamSettings.httpsettings = httpsettings streamSettings.httpSettings = httpsettings
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlssettingsBean() val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlsSettingsBean()
tlssettings.allowInsecure = true tlssettings.allowInsecure = true
streamSettings.tlssettings = tlssettings streamSettings.tlsSettings = tlssettings
} }
"quic" -> { "quic" -> {
val quicsettings = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean() val quicsettings = V2rayConfig.OutboundBean.StreamSettingsBean.QuicSettingBean()
val host = vmess.requestHost.trim() val host = vmess.requestHost.trim()
val path = vmess.path.trim() val path = vmess.path.trim()
quicsettings.security = host quicsettings.security = host
quicsettings.key = path quicsettings.key = path
quicsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean.HeaderBean() quicsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.QuicSettingBean.HeaderBean()
quicsettings.header.type = vmess.headerType quicsettings.header.type = vmess.headerType
streamSettings.quicsettings = quicsettings streamSettings.quicSettings = quicsettings
} }
else -> { else -> {
//tcp带http伪装 //tcp带http伪装
if (vmess.headerType == "http") { if (vmess.headerType == "http") {
val tcpSettings = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean() val tcpSettings = V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean()
tcpSettings.connectionReuse = true tcpSettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean()
tcpSettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean.HeaderBean()
tcpSettings.header.type = vmess.headerType tcpSettings.header.type = vmess.headerType
// if (requestObj.has("headers") // if (requestObj.has("headers")
@@ -4,12 +4,7 @@
tools:showIn="navigation_view"> tools:showIn="navigation_view">
<group <group
android:id="@+id/group_main" android:id="@+id/group_main">
android:checkableBehavior="single">
<item
android:id="@+id/server_profile"
android:icon="@drawable/ic_description_white_24dp"
android:title="@string/title_server" />
<item <item
android:id="@+id/sub_setting" android:id="@+id/sub_setting"
android:icon="@drawable/ic_subscriptions_white_24dp" android:icon="@drawable/ic_subscriptions_white_24dp"