Commit 2677cee4 authored by chenhuaqing's avatar chenhuaqing

code refactor

parent 116dee96
......@@ -7,6 +7,14 @@ data class NetState(
var accNetDelay: Int,
//丢包率
var lossRate: String
var lossRate: String,
var pingWifiLatency: Int = -1,
var pingWifiTotal: Int = -1,
var pingWifiLoss: Int = -1,
var pingCellularLatency: Int = -1,
var pingCellularTotal: Int = -1,
var pingCellularLoss: Int = -1,
)
\ No newline at end of file
......@@ -5,10 +5,11 @@ import androidx.lifecycle.ViewModelProvider
import androidx.viewpager.widget.ViewPager
import com.ccwangluo.accelerator.databinding.FragmentBtnNavBinding
import com.ccwangluo.accelerator.ui.home.AccelertorFragment
import com.ccwangluo.accelerator.ui.home.AcceleratorFragment
import com.ccwangluo.accelerator.ui.home.AccelertorViewModel
import com.ccwangluo.accelerator.ui.home.MineFragment
import com.ccwangluo.accelerator.ui.home.NewsFragment
import com.ccwangluo.accelerator.utils.AcceleratorUtils
import com.ccwangluo.accelerator.utils.LoginUtils
import com.ccwangluo.accelerator.utils.datareport.DataRePortUtils
import com.google.android.material.bottomnavigation.BottomNavigationView
......@@ -22,12 +23,12 @@ import com.xuexiang.xutil.common.CollectionUtils
@Page(name = "main")
class BottomNavigationFragment : XPageFragment(), ViewPager.OnPageChangeListener,
BottomNavigationView.OnNavigationItemSelectedListener {
private lateinit var accelertorViewModel: AccelertorViewModel
private lateinit var acceleratorViewModel: AccelertorViewModel
lateinit var binding: FragmentBtnNavBinding
override fun inflateView(inflater: LayoutInflater?, container: ViewGroup?): View {
binding = FragmentBtnNavBinding.inflate(inflater!!, container, false)
accelertorViewModel =
acceleratorViewModel =
ViewModelProvider(requireActivity()).get(AccelertorViewModel::class.java)
return binding.root
}
......@@ -39,7 +40,7 @@ class BottomNavigationFragment : XPageFragment(), ViewPager.OnPageChangeListener
var titles = arrayOf("加速", "资讯", "我的")
var fragments = arrayOf(
AccelertorFragment.newInstance(),
AcceleratorFragment.newInstance(),
NewsFragment.newInstance(),
MineFragment.newInstance()
)
......@@ -55,6 +56,8 @@ class BottomNavigationFragment : XPageFragment(), ViewPager.OnPageChangeListener
binding.viewPager.setOffscreenPageLimit(titles.size - 1);
binding.viewPager.adapter = adapter
binding.viewPager.setNoScroll(true)
AcceleratorUtils.initConnect(fragments[0] as AcceleratorFragment)
}
override fun initListeners() {
......@@ -78,7 +81,7 @@ class BottomNavigationFragment : XPageFragment(), ViewPager.OnPageChangeListener
LoginUtils.token?.let {
LoginUtils.getUserProfile(this) {
it?.let {
accelertorViewModel.userProfile.postValue(it)
acceleratorViewModel.userProfile.postValue(it)
}
}
}
......
......@@ -45,14 +45,14 @@ class MainActivity() : XPageActivity(), TencentLocationListener {
}
}
private lateinit var accelertorViewModel: AccelertorViewModel
private lateinit var acceleratorViewModel: AccelertorViewModel
private var mSensorEventListener: SensorEventListener? = null
private var mSensorManager: SensorManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
accelertorViewModel =
acceleratorViewModel =
ViewModelProvider(this).get(AccelertorViewModel::class.java)
// app 启动
if (SettingSPUtils.lastAPPOpenReportTime == 0L ||
......@@ -83,14 +83,14 @@ class MainActivity() : XPageActivity(), TencentLocationListener {
getPermission()
}
AcceleratorUtils.initConnect(this, connect)
AcceleratorUtils.initContext(this, connect)
mSensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
mSensorEventListener = JCVideoPlayer.JCAutoFullscreenListener()
DataRePortUtils.report("st_app_open")
}
fun getPermission() {
private fun getPermission() {
PermissionUtils.permission(Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
......
......@@ -12,6 +12,7 @@ import android.view.animation.RotateAnimation
import androidx.lifecycle.ViewModelProvider
import com.ccwangluo.accelerator.R
import com.ccwangluo.accelerator.databinding.FragmentQuickBinding
import com.ccwangluo.accelerator.model.NetState
import com.ccwangluo.accelerator.ui.dialog.CommonDialog
import com.ccwangluo.accelerator.ui.dialog.MemberDialog
import com.ccwangluo.accelerator.ui.web.CommonWebViewFragment
......@@ -30,11 +31,10 @@ import com.xuexiang.xpage.utils.TitleBar
import com.xuexiang.xui.widget.progress.CircleProgressView
import com.xuexiang.xutil.app.AppUtils
class AccelertorFragment : XPageFragment() {
class AcceleratorFragment : XPageFragment() {
private lateinit var binding: FragmentQuickBinding
private lateinit var accelertorViewModel: AccelertorViewModel
private var acc_timer = 0L
private lateinit var acceleratorViewModel: AccelertorViewModel
private var accTimer = 0L
override fun initTitleBar(): TitleBar? {
//不使用@Page标注的一定要注意覆盖这个方法
......@@ -43,16 +43,25 @@ class AccelertorFragment : XPageFragment() {
var state: BaseService.State? = null
fun updateNetState(netState: NetState) {
acceleratorViewModel.netState.postValue(netState)
accTimer = AcceleratorUtils.getAccTime()
}
fun changeState(state: BaseService.State) {
acceleratorViewModel.accState.postValue(state)
}
override fun inflateView(inflater: LayoutInflater?, container: ViewGroup?): View {
binding = FragmentQuickBinding.inflate(inflater!!, container, false)
accelertorViewModel =
acceleratorViewModel =
ViewModelProvider(requireActivity()).get(AccelertorViewModel::class.java)
return binding.root
}
override fun initViews() {
accelertorViewModel.netState.observe(this, {
acceleratorViewModel.netState.observe(this, {
if (it.preNetDelay != -1) { //有网络
binding.preDelay1.setText(it.preNetDelay.toString())
......@@ -99,8 +108,8 @@ class AccelertorFragment : XPageFragment() {
binding.activeNetwork.setText(SysUtils.getActiveNet())
})
accelertorViewModel.accState.observe(this, {
binding.accStateTx.setText(SysUtils.getAccTimeString(acc_timer))
acceleratorViewModel.accState.observe(this, {
binding.accStateTx.setText(SysUtils.getAccTimeString(accTimer))
state = it
freshData(it)
if (SettingSPUtils.isSmartAccOpen) {
......@@ -114,7 +123,7 @@ class AccelertorFragment : XPageFragment() {
}
})
accelertorViewModel.userProfile.observe(this, {
acceleratorViewModel.userProfile.observe(this, {
if (it.hasUnreadNotice) {
binding.iconNoticeBadge.visibility = View.VISIBLE
} else {
......@@ -136,7 +145,7 @@ class AccelertorFragment : XPageFragment() {
binding.progressArea.visibility = View.GONE
binding.btnQuick.isEnabled = true
binding.progressViewCircleSmall.progress = 0F
AcceleratorUtils.startAccelerator(this@AccelertorFragment)
AcceleratorUtils.startAccelerator(this@AcceleratorFragment)
}
})
......@@ -196,7 +205,7 @@ class AccelertorFragment : XPageFragment() {
}
}
binding.btnQuick.setOnClickListener {
accelertorViewModel.accState.value?.let {
acceleratorViewModel.accState.value?.let {
if (it.canStop) {
context?.let {
CommonDialog(it).setTitle("加速停止确认")
......@@ -252,7 +261,7 @@ class AccelertorFragment : XPageFragment() {
}
}
//用户是否有使用时长
LoginUtils.getUserHasTimer(this@AccelertorFragment) {
LoginUtils.getUserHasTimer(this@AcceleratorFragment) {
if (it) {
binding.btnQuick.isEnabled = false
startAnim()
......@@ -261,7 +270,7 @@ class AccelertorFragment : XPageFragment() {
"st_speed_result",
mapOf("result" to 0, "cause" to 3)
)
MemberDialog(this@AccelertorFragment).show<MemberDialog>()
MemberDialog(this@AcceleratorFragment).show<MemberDialog>()
}
}
} else {
......@@ -375,7 +384,7 @@ class AccelertorFragment : XPageFragment() {
LoginUtils.token?.let {
LoginUtils.getUserProfile(this) {
it?.let {
accelertorViewModel.userProfile.postValue(it)
acceleratorViewModel.userProfile.postValue(it)
}
}
}
......@@ -384,7 +393,7 @@ class AccelertorFragment : XPageFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AcceleratorUtils.registerVipExpireListener {
MemberDialog(this@AccelertorFragment).show<MemberDialog>()
MemberDialog(this@AcceleratorFragment).show<MemberDialog>()
}
}
......@@ -396,18 +405,18 @@ class AccelertorFragment : XPageFragment() {
override fun onStart() {
super.onStart()
AcceleratorUtils.registerStateListener { state, l, net ->
net?.let {
accelertorViewModel.netState.postValue(net)
}
acc_timer = l
accelertorViewModel.accState.postValue(state)
}
// AcceleratorUtils.registerStateListener { state, l, net ->
// net?.let {
// acceleratorViewModel.netState.postValue(net)
// }
// accTimer = l
// acceleratorViewModel.accState.postValue(state)
// }
}
override fun onStop() {
super.onStop()
AcceleratorUtils.unRegisterStateListener()
// AcceleratorUtils.unRegisterStateListener()
}
override fun onResume() {
......@@ -462,9 +471,8 @@ class AccelertorFragment : XPageFragment() {
}
companion object {
fun newInstance(): AccelertorFragment {
val fragment = AccelertorFragment()
return fragment
fun newInstance(): AcceleratorFragment {
return AcceleratorFragment()
}
}
......
package com.ccwangluo.accelerator.utils
import android.net.Network
import com.github.shadowsocks.net.DefaultNetworkListener
import kotlinx.coroutines.isActive
import timber.log.Timber
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.Socket
import java.net.UnknownHostException
import kotlin.coroutines.coroutineContext
object NetUtils {
@Volatile
private var underlyingNetwork: Network? = null
suspend fun init() {
DefaultNetworkListener.start(this) {
underlyingNetwork = it
}
}
suspend fun tcpPing(url: String, port: Int, proxyPort: Int = 0): Long {
var time = -1L
for (k in 0 until 2) {
......@@ -25,12 +35,16 @@ object NetUtils {
return time
}
private fun socketConnectTime(url: String, port: Int, proxyPort: Int): Long {
private suspend fun socketConnectTime(url: String, port: Int, proxyPort: Int): Long {
try {
val socket = if (proxyPort == 0) {
Socket()
} else {
Socket(Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", proxyPort)))
val socket = Socket()
DefaultNetworkListener.get().bindSocket(socket)
socket
// Socket(Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", proxyPort)))
}
val start = System.currentTimeMillis()
socket.connect(InetSocketAddress(url, port))
......
{
"formatVersion": 1,
"database": {
"version": 30,
"identityHash": "c6293b758903bd4b8084f9d2f0ce9763",
"entities": [
{
"tableName": "Profile",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `host` TEXT NOT NULL, `remotePort` INTEGER NOT NULL, `password` TEXT NOT NULL, `token` TEXT, `method` TEXT NOT NULL, `authTimeout` INTEGER NOT NULL, `beatsInterval` INTEGER NOT NULL, `retryLimit` INTEGER NOT NULL, `route` TEXT NOT NULL, `remoteDns` TEXT NOT NULL, `proxyApps` INTEGER NOT NULL, `bypass` INTEGER NOT NULL, `udpdns` INTEGER NOT NULL, `ipv6` INTEGER NOT NULL, `metered` INTEGER NOT NULL, `individual` TEXT NOT NULL, `plugin` TEXT, `udpFallback` INTEGER, `subscription` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "host",
"columnName": "host",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "remotePort",
"columnName": "remotePort",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "token",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "method",
"columnName": "method",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "authTimeout",
"columnName": "authTimeout",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "beatsInterval",
"columnName": "beatsInterval",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "retryLimit",
"columnName": "retryLimit",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "route",
"columnName": "route",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "remoteDns",
"columnName": "remoteDns",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "proxyApps",
"columnName": "proxyApps",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bypass",
"columnName": "bypass",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "udpdns",
"columnName": "udpdns",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ipv6",
"columnName": "ipv6",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "metered",
"columnName": "metered",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "individual",
"columnName": "individual",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "plugin",
"columnName": "plugin",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "udpFallback",
"columnName": "udpFallback",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "subscription",
"columnName": "subscription",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tx",
"columnName": "tx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rx",
"columnName": "rx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "KeyValuePair",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "valueType",
"columnName": "valueType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"key"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c6293b758903bd4b8084f9d2f0ce9763')"
]
}
}
\ No newline at end of file
......@@ -10,4 +10,5 @@ interface IShadowsocksService {
void startListeningForBandwidth(in IShadowsocksServiceCallback cb, long timeout);
oneway void stopListeningForBandwidth(in IShadowsocksServiceCallback cb);
oneway void unregisterCallback(in IShadowsocksServiceCallback cb);
oneway void bindNetwork(int networkMode);
}
package com.ccnet.acc
import android.content.Context
import com.github.shadowsocks.database.Profile
import timber.log.Timber
import java.io.File
object AccVpn {
private const val configFilename = "config.conf"
fun configFile(context: Context): File {
return File(context.filesDir, configFilename)
}
fun writeConfig(context: Context, tunFd: Int, profile: Profile) {
val configContent = """
[General]
loglevel = trace
dns-server = 223.5.5.5
tun-fd = ${tunFd}
[Proxy]
Direct = direct
SS = ss, ${profile.host}, ${profile.remotePort}, encrypt-method=chacha20-ietf-poly1305, password=123456, auth_timeout=${profile.authTimeout}, beats_interval=${profile.beatsInterval}, retry_limit=${profile.retryLimit}, token=${profile.token}
[Rule]
FINAL, SS
"""
val configFile = configFile(context)
Timber.d("writeConfig ${configFile.absolutePath}")
configFile.writeText(configContent)
}
}
\ No newline at end of file
package com.ccnet.acc
class AccVpnService {
companion object {
private val INSTANCE = AccVpnService()
val instance: AccVpnService
get() {
return INSTANCE
}
}
init {
System.loadLibrary("ccnetacc")
}
external fun runAcc(
configPath: String,
protectPath: String,
networkClass: String,
callback: String
)
external fun testLatency(
proxyHost: String,
proxyPort: Int,
testHost: String,
intervalSec: Int,
timeoutMillis: Int,
callback: TestLatencyCallback
): Int
external fun stopAcc()
}
interface TestLatencyCallback {
fun onLatency(latency: Int)
}
\ No newline at end of file
package com.ccnet.acc
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import timber.log.Timber
import java.io.FileDescriptor
import java.io.IOException
import java.lang.reflect.Field
object NetworkAdapter {
val JNI_CLAZZ_NAME = NetworkAdapter::class.java.name.replace(".", "/")
var wifiNetwork: Network? = null
var cellularNetwork: Network? = null
private var bindNetwork: Network? = null
private val FD_FIELD: Field
val wifiRequest: NetworkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
val cellularRequest: NetworkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
fun initNetworks(context: Context) {
connectivityManager(context).requestNetwork(wifiRequest, object : NetworkCallback() {
override fun onAvailable(network: Network) {
wifiNetwork = network
}
override fun onLost(network: Network) {
wifiNetwork = null
}
})
connectivityManager(context).requestNetwork(cellularRequest, object : NetworkCallback() {
override fun onAvailable(network: Network) {
cellularNetwork = network
}
override fun onLost(network: Network) {
cellularNetwork = null
}
})
}
fun useWifi(context: Context) {
connectivityManager(context).requestNetwork(wifiRequest, object : NetworkCallback() {
override fun onAvailable(network: Network) {
bindNetwork = network
}
override fun onLost(network: Network) {
bindNetwork = null
}
})
}
fun useCellular(context: Context) {
connectivityManager(context).requestNetwork(cellularRequest, object : NetworkCallback() {
override fun onAvailable(network: Network) {
bindNetwork = network
}
override fun onLost(network: Network) {
bindNetwork = null
}
})
}
fun useSystem() {
bindNetwork = null
}
private fun connectivityManager(context: Context): ConnectivityManager {
return context.getSystemService(ConnectivityManager::class.java)
}
@JvmStatic
fun bindSocket(rawFd: Int) {
val bindNetwork = bindNetwork ?: return
val fd = FileDescriptor()
try {
FD_FIELD[fd] = rawFd
NetworkAdapter.bindNetwork!!.bindSocket(fd)
Timber.d("bind socket success")
} catch (e: IllegalAccessException) {
// ignore
Timber.e("bind socket failed $e")
} catch (e: IOException) {
Timber.e("bind socket failed $e")
}
}
init {
try {
@SuppressLint("DiscouragedPrivateApi")
FD_FIELD = FileDescriptor::class.java.getDeclaredField("descriptor")
} catch (e: NoSuchFieldException) {
throw RuntimeException(e)
}
FD_FIELD.isAccessible = true
}
}
\ No newline at end of file
package com.ccnet.acc.aidl
enum class NetworkMode(val code: Int) {
WIFI(0),
CELLULAR(1),
SYSTEM(2),
}
\ No newline at end of file
package com.ccnet.acc.common
object Constants {
const val CONFIG_PREFERENCE = "config_preference"
const val ACC_CONFIG_KEY = "acc_config_key"
}
\ No newline at end of file
package com.ccnet.acc.native
interface NativeCallback {
enum class ErrorCode(val code: Int) {
AuthFailed(1001),
NetworkBindSocketFailed(1002),
NetworkError(1003),
UnknownError(1004),
;
companion object {
private val VALUES = values().associateBy { it.code }
fun from(code: Int): ErrorCode {
return VALUES[code] ?: UnknownError
}
}
}
fun onStart()
fun onError(code: ErrorCode, error: String)
fun onFatal(code: ErrorCode, error: String)
}
\ No newline at end of file
package com.ccnet.acc.native
object VpnNativeDispatcher {
val JNI_CLAZZ_NAME = VpnNativeDispatcher::class.java.name.replace(".", "/")
private val NATIVE_CALLBACKS: MutableMap<String, NativeCallback> = mutableMapOf()
@JvmStatic
fun registerCallback(key: String, listener: NativeCallback) {
NATIVE_CALLBACKS[key] = listener
}
@JvmStatic
private fun onStart() {
for (eventListener in NATIVE_CALLBACKS.values) {
eventListener.onStart()
}
}
@JvmStatic
fun onError(code: Int, error: String) {
for (eventListener in NATIVE_CALLBACKS.values) {
eventListener.onError(NativeCallback.ErrorCode.from(code), error)
}
}
@JvmStatic
fun onFatal(code: Int, error: String) {
for (eventListener in NATIVE_CALLBACKS.values) {
eventListener.onFatal(NativeCallback.ErrorCode.from(code), error)
}
}
}
\ No newline at end of file
......@@ -41,12 +41,6 @@ import kotlinx.coroutines.launch
class ShadowsocksConnection(private var listenForDeath: Boolean = false) : ServiceConnection, IBinder.DeathRecipient {
companion object {
val serviceClass get() = VpnService::class.java
// when (DataStore.serviceMode) {
// Key.modeProxy -> ProxyService::class
// Key.modeVpn -> VpnService::class
// Key.modeTransproxy -> TransproxyService::class
// else -> throw UnknownError()
// }.java
}
interface Callback {
......
......@@ -31,9 +31,13 @@ data class TrafficStats(
// Bytes for the current session
var txTotal: Long = 0L,
var rxTotal: Long = 0L
var rxTotal: Long = 0L,
// round trip latency
var latency: Int = 0,
) : Parcelable {
operator fun plus(other: TrafficStats) = TrafficStats(
txRate + other.txRate, rxRate + other.rxRate,
txTotal + other.txTotal, rxTotal + other.rxTotal)
txTotal + other.txTotal, rxTotal + other.rxTotal, other.latency
)
}
package com.github.shadowsocks.bg
import android.os.Build
import android.util.Log
import com.ccnet.acc.AccVpn
import com.github.shadowsocks.Core
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.http.*
import com.github.shadowsocks.preference.DataStore
import com.google.gson.Gson
import com.google.gson.JsonStreamParser
import com.google.gson.reflect.TypeToken
......@@ -94,6 +95,9 @@ object AuthManager {
profile.host = lineConfig.host
profile.token = lineConfig.token
profile.remotePort = lineConfig.port
DataStore.pingProxyServer = profile.host
DataStore.pingProxyPort = profile.remotePort + 1
Timber.d("start vpn with games: ${profile.individual}, profileId: ${profile.id}, route: ${profile.route}")
ProfileManager.updateProfile(profile)
} else if (lineConfigResult.code == 1001) {
......@@ -129,6 +133,10 @@ object AuthManager {
proxyInstance.profile.token = refreshTokenResult.unwrapData().token
configJson.addProperty("token", proxyInstance.profile.token)
configFile.writeText(configJson.toString())
data.tunFd?.let {
AccVpn.writeConfig(Core.app, it, proxyInstance.profile)
}
return@let
} else if (refreshTokenResult.code == 1001) {
failedCount=0
throw AuthException(refreshTokenResult.error!!)
......@@ -157,7 +165,7 @@ object AuthManager {
): ApiResult<T> {
val body: RequestBody = gson.toJson(params).toString().toRequestBody(jsonType)
val request = Request.Builder()
.url(HttpConfig.baseUrl + url)
.url(if (url.startsWith("http")) url else HttpConfig.baseUrl + url)
.post(body)
token?.let {
request.addHeader("Authorization", it)
......
......@@ -28,6 +28,10 @@ import android.os.Build
import android.os.IBinder
import android.os.RemoteCallbackList
import android.os.RemoteException
import com.ccnet.acc.NetworkAdapter
import com.ccnet.acc.aidl.NetworkMode
import com.ccnet.acc.native.NativeCallback
import com.ccnet.acc.native.VpnNativeDispatcher
import com.github.shadowsocks.BootReceiver
import com.github.shadowsocks.Core
import com.github.shadowsocks.Core.app
......@@ -43,7 +47,6 @@ import com.github.shadowsocks.utils.broadcastReceiver
import com.github.shadowsocks.utils.readableMessage
import kotlinx.coroutines.*
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.net.URL
......@@ -74,6 +77,7 @@ object BaseService {
var proxy: ProxyInstance? = null
var udpFallback: ProxyInstance? = null
var localDns: LocalDnsWorker? = null
var tunFd: Int? = null
var notification: ServiceNotification? = null
val closeReceiver = broadcastReceiver { _, intent ->
......@@ -192,6 +196,14 @@ object BaseService {
callbacks.unregister(cb)
}
override fun bindNetwork(networkMode: Int) {
when (networkMode) {
NetworkMode.WIFI.code -> NetworkAdapter.useWifi(app)
NetworkMode.CELLULAR.code -> NetworkAdapter.useCellular(app)
NetworkMode.SYSTEM.code -> NetworkAdapter.useSystem()
}
}
fun stateChanged(s: State, msg: String?) = launch {
val profileName = profileName
broadcast { it.stateChanged(s.ordinal, profileName, msg) }
......@@ -229,20 +241,20 @@ object BaseService {
val isVpnService get() = false
suspend fun startProcesses() {
val context = if (Build.VERSION.SDK_INT < 24 || Core.user.isUserUnlocked) app else Core.deviceStorage
val configRoot = context.noBackupFilesDir
val udpFallback = data.udpFallback
data.proxy!!.start(this,
File(Core.deviceStorage.noBackupFilesDir, "stat_main"),
File(configRoot, CONFIG_FILE),
if (udpFallback == null && data.proxy?.plugin == null) "tcp_and_udp" else "tcp_only")
if (udpFallback?.plugin != null) throw ExpectedExceptionWrapper(IllegalStateException(
"UDP fallback cannot have plugins"))
udpFallback?.start(this,
File(Core.deviceStorage.noBackupFilesDir, "stat_udp"),
File(configRoot, CONFIG_FILE_UDP),
"udp_only", false)
data.localDns = LocalDnsWorker(this::rawResolver).apply { start() }
// val context = if (Build.VERSION.SDK_INT < 24 || Core.user.isUserUnlocked) app else Core.deviceStorage
// val configRoot = context.noBackupFilesDir
// val udpFallback = data.udpFallback
// data.proxy!!.start(this,
// File(Core.deviceStorage.noBackupFilesDir, "stat_main"),
// File(configRoot, CONFIG_FILE),
// if (udpFallback == null && data.proxy?.plugin == null) "tcp_and_udp" else "tcp_only")
// if (udpFallback?.plugin != null) throw ExpectedExceptionWrapper(IllegalStateException(
// "UDP fallback cannot have plugins"))
// udpFallback?.start(this,
// File(Core.deviceStorage.noBackupFilesDir, "stat_udp"),
// File(configRoot, CONFIG_FILE_UDP),
// "udp_only", false)
// data.localDns = LocalDnsWorker(this::rawResolver).apply { start() }
}
fun startRunner() {
......@@ -346,7 +358,8 @@ object BaseService {
data.changeState(State.Connecting)
data.connectingJob = GlobalScope.launch(Dispatchers.Main) {
try {
Executable.killAll() // clean up old processes
AuthManager.initAuthProfile(profile)
// Executable.killAll() // clean up old processes
preInit()
if (profile.route == Acl.CUSTOM_RULES) try {
withContext(Dispatchers.IO) {
......@@ -362,12 +375,28 @@ object BaseService {
Timber.w(it)
stopRunner(false, it.readableMessage)
}
startProcesses()
VpnNativeDispatcher.registerCallback(this.javaClass.name,
object : NativeCallback {
override fun onStart() {
data.changeState(State.Connected)
}
data.proxy!!.scheduleUpdate()
data.udpFallback?.scheduleUpdate()
override fun onError(code: NativeCallback.ErrorCode, error: String) {
}
data.changeState(State.Connected)
override fun onFatal(code: NativeCallback.ErrorCode, error: String) {
Timber.e("base service onFatal $code, $error")
if (code == NativeCallback.ErrorCode.NetworkError) {
stopRunner(true, error)
} else {
stopRunner(false, error)
}
}
})
startProcesses()
// data.proxy!!.scheduleUpdate()
// data.udpFallback?.scheduleUpdate()
} catch (_: CancellationException) {
// if the job was cancelled, it is canceller's responsibility to call stopRunner
} catch (exc: Throwable) {
......
......@@ -52,7 +52,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
}
}
private var configFile: File? = null
var trafficMonitor: TrafficMonitor? = null
var trafficMonitor: TrafficMonitor? = TrafficMonitor(null)
val plugin by lazy { PluginManager.init(PluginConfiguration(profile.plugin ?: "")) }
/**
......@@ -120,6 +120,8 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
Timber.d("start vpn service with acl ${Acl.getFile(route).readText()}")
}
// DataStore.outboundBindInterface = "rmnet_data1"
if (DataStore.outboundBindInterface.isNotBlank()) {
cmd += "--outbound-bind-interface"
cmd += DataStore.outboundBindInterface
......
......@@ -22,24 +22,35 @@ package com.github.shadowsocks.bg
import android.net.LocalSocket
import android.os.SystemClock
import com.ccnet.acc.AccVpnService
import com.ccnet.acc.TestLatencyCallback
import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.net.LocalSocketListener
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot
import kotlinx.coroutines.CoroutineScope
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.ByteOrder
class TrafficMonitor(statFile: File) {
val thread = object : LocalSocketListener("TrafficMonitor-" + statFile.name, statFile) {
class TrafficMonitor(statFile: File?) {
interface DisposableTasker {
fun shutdown(scope: CoroutineScope)
}
val thread: DisposableTasker = if (statFile != null) {
object : LocalSocketListener("TrafficMonitor-" + statFile.name, statFile),
DisposableTasker {
private val buffer = ByteArray(16)
private val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
override fun acceptInternal(socket: LocalSocket) {
when (val read = socket.inputStream.read(buffer)) {
-1 -> return
16 -> { }
16 -> {
}
else -> throw IOException("Unexpected traffic stat length $read")
}
val tx = stat.getLong(0)
......@@ -54,6 +65,40 @@ class TrafficMonitor(statFile: File) {
}
}
}.apply { start() }
} else {
object : Thread("TrafficMonitor-NativePing"), DisposableTasker {
@Volatile
private var running = true
override fun run() {
Timber.d("TrafficMonitor-NativePing prepare test ${DataStore.pingAccHost}:${DataStore.pingAccPort}")
while (running) {
val resultCode = AccVpnService.instance.testLatency(
DataStore.pingProxyServer,
DataStore.pingProxyPort,
DataStore.pingAccHost,
DataStore.pingIntervalSec,
DataStore.pingTimeoutMillis,
object : TestLatencyCallback {
override fun onLatency(latency: Int) {
Timber.d("TrafficMonitor-NativeTcpPing test ${current.latency}")
current.latency = latency
dirty = true
}
}
)
if (resultCode != 0) {
Timber.d("TrafficMonitor-NativeTcpPing exited with $resultCode")
}
sleep(DataStore.pingIntervalSec.toLong())
}
}
override fun shutdown(scope: CoroutineScope) {
running = false
}
}.apply { start() }
}
val current = TrafficStats()
var out = TrafficStats()
......
......@@ -6,6 +6,9 @@ object HttpConfig {
//val baseUrl = "http://10.16.1.98:9002"
// val baseUrl = "https://test-cc-tt-api.orangenet.org.cn" //测试
val baseUrl = "https://cc-tt-front.srccwl.com" //生产
// val baseUrl = "http://192.168.137.25:9002"
// val baseUrl = "https://test-cc-tt-api.orangenet.org.cn" //测试
// val baseUrl = "https://cc-tt-front.srccwl.com" //生产
/**
......
......@@ -92,7 +92,8 @@ object DefaultNetworkListener {
// NB: this runs in ConnectivityThread, and this behavior cannot be changed until API 26
private object Callback : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) = runBlocking { networkActor.send(NetworkMessage.Put(network)) }
override fun onAvailable(network: Network) = runBlocking {
networkActor.send(NetworkMessage.Put(network)) }
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
// it's a good idea to refresh capabilities
runBlocking { networkActor.send(NetworkMessage.Update(network)) }
......
......@@ -110,4 +110,25 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var outboundBindInterface: String
get() = privateStore.getString(Key.outboundBindInterface) ?: ""
set(value) = privateStore.putString(Key.outboundBindInterface, value)
var pingProxyServer: String
get() = privateStore.getString(Key.pingProxyServer) ?: ""
set(value) = privateStore.putString(Key.pingProxyServer, value)
var pingProxyPort: Int
get() = privateStore.getInt(Key.pingProxyPort) ?: 0
set(value) = privateStore.putInt(Key.pingProxyPort, value)
var pingIntervalSec: Int
get() = privateStore.getInt(Key.pingIntervalSec) ?: 3
set(value) = privateStore.putInt(Key.pingIntervalSec, value)
var pingTimeoutMillis: Int
get() = privateStore.getInt(Key.pingTimeoutMillis) ?: 200
set(value) = privateStore.putInt(Key.pingTimeoutMillis, value)
var pingAccHost: String
get() = privateStore.getString(Key.pingAccHost) ?: ""
set(value) = privateStore.putString(Key.pingAccHost, value)
var pingAccPort: Int
get() = privateStore.getInt(Key.pingAccPort) ?: 80
set(value) = privateStore.putInt(Key.pingAccPort, value)
var pingNetReachableHost: String
get() = privateStore.getString(Key.pingNetReachableHost) ?: "baidu.com"
set(value) = privateStore.putString(Key.pingNetReachableHost, value)
}
......@@ -71,6 +71,14 @@ object Key {
const val assetUpdateTime = "assetUpdateTime"
const val pingProxyServer = "pingProxyServer"
const val pingProxyPort = "pingProxyPort"
const val pingIntervalSec = "pingIntervalSec"
const val pingTimeoutMillis = "pingTimeoutMillis"
const val pingAccHost = "pingAccHost"
const val pingAccPort = "pingAccPort"
const val pingNetReachableHost = "pingNetReachableHost"
// TV specific values
const val controlStats = "control.stats"
const val controlImport = "control.import"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment