Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28639cc388 | |||
| ca254b2aa1 | |||
| 9721879713 | |||
| 623c1807c5 | |||
| 739fa88ba7 | |||
| 85d6f00f8c | |||
| 8986710453 | |||
| f54faacbf6 | |||
| 903352ec9c | |||
| ad56106c08 | |||
| aea8369b8a | |||
| 92d2cb35c4 | |||
| 6ce3d540e8 | |||
| 8b149fb52f |
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user