feat: clash api selector callback

This commit is contained in:
arm64v8a 2023-04-21 09:59:21 +09:00
parent 46526560d8
commit dd648447eb
20 changed files with 177 additions and 46 deletions

View File

@ -9,4 +9,5 @@ oneway interface ISagerNetServiceCallback {
void routeAlert(int type, String routeName); void routeAlert(int type, String routeName);
void cbSpeedUpdate(in SpeedDisplayData stats); void cbSpeedUpdate(in SpeedDisplayData stats);
void cbTrafficUpdate(in TrafficData stats); void cbTrafficUpdate(in TrafficData stats);
void cbSelectorUpdate(long id);
} }

View File

@ -20,7 +20,9 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import go.Seq import go.Seq
import io.nekohasekai.sagernet.bg.SagerConnection import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.bg.ServiceNotification
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import io.nekohasekai.sagernet.ui.MainActivity import io.nekohasekai.sagernet.ui.MainActivity
@ -266,4 +268,22 @@ class SagerNet : Application(),
return DataStore.rulesProvider == 0 return DataStore.rulesProvider == 0
} }
override fun selector_OnProxySelected(tag: String) {
DataStore.baseService?.apply {
runOnDefaultDispatcher {
val id = data.proxy!!.config.profileTagMap
.filterValues { it == tag }.keys.firstOrNull() ?: -1
val ent = SagerDatabase.proxyDao.getById(id) ?: return@runOnDefaultDispatcher
// traffic & title
data.proxy!!.looper?.selectMain(id)
val title = ServiceNotification.genTitle(ent)
data.notification?.postNotificationTitle(title)
// post MainActivity animation
data.binder.broadcast { b ->
b.cbSelectorUpdate(id)
}
}
}
}
} }

View File

@ -58,6 +58,7 @@ class BaseService {
.show() .show()
} }
} }
else -> service.stopRunner() else -> service.stopRunner()
} }
} }
@ -165,12 +166,10 @@ class BaseService {
val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy) val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy)
val tag = data.proxy!!.config.profileTagMap[ent?.id] ?: "" val tag = data.proxy!!.config.profileTagMap[ent?.id] ?: ""
if (tag.isNotBlank() && ent != null) { if (tag.isNotBlank() && ent != null) {
val success = data.proxy!!.box.selectOutbound(tag) // select from GUI
if (success) runOnDefaultDispatcher { data.proxy!!.box.selectOutbound(tag)
data.proxy!!.looper?.selectMain(ent.id) // or select from webui
val title = ServiceNotification.genTitle(ent) // => selector_OnProxySelected
data.notification?.postNotificationTitle(title)
}
} }
return return
} }

View File

@ -39,6 +39,7 @@ class SagerConnection(
fun cbSpeedUpdate(stats: SpeedDisplayData) {} fun cbSpeedUpdate(stats: SpeedDisplayData) {}
fun cbTrafficUpdate(data: TrafficData) {} fun cbTrafficUpdate(data: TrafficData) {}
fun cbSelectorUpdate(id: Long) {}
fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) fun stateChanged(state: BaseService.State, profileName: String?, msg: String?)
@ -83,6 +84,13 @@ class SagerConnection(
} }
} }
override fun cbSelectorUpdate(id: Long) {
val callback = callback ?: return
runOnMainDispatcher {
callback.cbSelectorUpdate(id)
}
}
override fun missingPlugin(profileName: String, pluginName: String) { override fun missingPlugin(profileName: String, pluginName: String) {
val callback = callback ?: return val callback = callback ?: return
runOnMainDispatcher { runOnMainDispatcher {

View File

@ -9,6 +9,7 @@ import io.nekohasekai.sagernet.database.ProfileManager
import io.nekohasekai.sagernet.fmt.TAG_BYPASS import io.nekohasekai.sagernet.fmt.TAG_BYPASS
import io.nekohasekai.sagernet.fmt.TAG_PROXY import io.nekohasekai.sagernet.fmt.TAG_PROXY
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import kotlinx.coroutines.* import kotlinx.coroutines.*
class TrafficLooper class TrafficLooper
@ -55,14 +56,22 @@ class TrafficLooper
fun selectMain(id: Long) { fun selectMain(id: Long) {
Logs.d("select traffic count $TAG_PROXY to $id, old id is $selectorNowId") Logs.d("select traffic count $TAG_PROXY to $id, old id is $selectorNowId")
val oldData = items[selectorNowId] val oldData = items[selectorNowId]
val data = items[id] ?: return val newData = items[id] ?: return
oldData?.apply { oldData?.apply {
tag = selectorNowFakeTag tag = selectorNowFakeTag
ignore = true ignore = true
// post traffic when switch
data.proxy?.config?.trafficMap?.get(tag)?.firstOrNull()?.let {
it.rx = rx
it.tx = tx
runOnDefaultDispatcher {
ProfileManager.updateProfile(it) // update DB
} }
selectorNowFakeTag = data.tag }
}
selectorNowFakeTag = newData.tag
selectorNowId = id selectorNowId = id
data.apply { newData.apply {
tag = TAG_PROXY tag = TAG_PROXY
ignore = false ignore = false
} }

View File

@ -17,7 +17,7 @@ object ProfileManager {
interface Listener { interface Listener {
suspend fun onAdd(profile: ProxyEntity) suspend fun onAdd(profile: ProxyEntity)
suspend fun onUpdated(data: TrafficData) suspend fun onUpdated(data: TrafficData)
suspend fun onUpdated(profile: ProxyEntity) suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean)
suspend fun onRemoved(groupId: Long, profileId: Long) suspend fun onRemoved(groupId: Long, profileId: Long)
} }
@ -87,13 +87,13 @@ object ProfileManager {
suspend fun updateProfile(profile: ProxyEntity) { suspend fun updateProfile(profile: ProxyEntity) {
SagerDatabase.proxyDao.updateProxy(profile) SagerDatabase.proxyDao.updateProxy(profile)
iterator { onUpdated(profile) } iterator { onUpdated(profile, false) }
} }
suspend fun updateProfile(profiles: List<ProxyEntity>) { suspend fun updateProfile(profiles: List<ProxyEntity>) {
SagerDatabase.proxyDao.updateProxy(profiles) SagerDatabase.proxyDao.updateProxy(profiles)
profiles.forEach { profiles.forEach {
iterator { onUpdated(it) } iterator { onUpdated(it, false) }
} }
} }
@ -141,12 +141,12 @@ object ProfileManager {
// postUpdate: post to listeners, don't change the DB // postUpdate: post to listeners, don't change the DB
suspend fun postUpdate(profileId: Long) { suspend fun postUpdate(profileId: Long, noTraffic: Boolean = false) {
postUpdate(getProfile(profileId) ?: return) postUpdate(getProfile(profileId) ?: return, noTraffic)
} }
suspend fun postUpdate(profile: ProxyEntity) { suspend fun postUpdate(profile: ProxyEntity, noTraffic: Boolean = false) {
iterator { onUpdated(profile) } iterator { onUpdated(profile, noTraffic) }
} }
suspend fun postUpdate(data: TrafficData) { suspend fun postUpdate(data: TrafficData) {

View File

@ -293,6 +293,7 @@ class ConfigurationFragment @JvmOverloads constructor(
R.id.action_scan_qr_code -> { R.id.action_scan_qr_code -> {
startActivity(Intent(context, ScannerActivity::class.java)) startActivity(Intent(context, ScannerActivity::class.java))
} }
R.id.action_import_clipboard -> { R.id.action_import_clipboard -> {
val text = SagerNet.getClipboardText() val text = SagerNet.getClipboardText()
if (text.isBlank()) { if (text.isBlank()) {
@ -314,56 +315,73 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
} }
R.id.action_import_file -> { R.id.action_import_file -> {
startFilesForResult(importFile, "*/*") startFilesForResult(importFile, "*/*")
} }
R.id.action_new_socks -> { R.id.action_new_socks -> {
startActivity(Intent(requireActivity(), SocksSettingsActivity::class.java)) startActivity(Intent(requireActivity(), SocksSettingsActivity::class.java))
} }
R.id.action_new_http -> { R.id.action_new_http -> {
startActivity(Intent(requireActivity(), HttpSettingsActivity::class.java)) startActivity(Intent(requireActivity(), HttpSettingsActivity::class.java))
} }
R.id.action_new_ss -> { R.id.action_new_ss -> {
startActivity(Intent(requireActivity(), ShadowsocksSettingsActivity::class.java)) startActivity(Intent(requireActivity(), ShadowsocksSettingsActivity::class.java))
} }
R.id.action_new_vmess -> { R.id.action_new_vmess -> {
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java)) startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java))
} }
R.id.action_new_vless -> { R.id.action_new_vless -> {
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java).apply { startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java).apply {
putExtra("vless", true) putExtra("vless", true)
}) })
} }
R.id.action_new_trojan -> { R.id.action_new_trojan -> {
startActivity(Intent(requireActivity(), TrojanSettingsActivity::class.java)) startActivity(Intent(requireActivity(), TrojanSettingsActivity::class.java))
} }
R.id.action_new_trojan_go -> { R.id.action_new_trojan_go -> {
startActivity(Intent(requireActivity(), TrojanGoSettingsActivity::class.java)) startActivity(Intent(requireActivity(), TrojanGoSettingsActivity::class.java))
} }
R.id.action_new_naive -> { R.id.action_new_naive -> {
startActivity(Intent(requireActivity(), NaiveSettingsActivity::class.java)) startActivity(Intent(requireActivity(), NaiveSettingsActivity::class.java))
} }
R.id.action_new_hysteria -> { R.id.action_new_hysteria -> {
startActivity(Intent(requireActivity(), HysteriaSettingsActivity::class.java)) startActivity(Intent(requireActivity(), HysteriaSettingsActivity::class.java))
} }
R.id.action_new_tuic -> { R.id.action_new_tuic -> {
startActivity(Intent(requireActivity(), TuicSettingsActivity::class.java)) startActivity(Intent(requireActivity(), TuicSettingsActivity::class.java))
} }
R.id.action_new_ssh -> { R.id.action_new_ssh -> {
startActivity(Intent(requireActivity(), SSHSettingsActivity::class.java)) startActivity(Intent(requireActivity(), SSHSettingsActivity::class.java))
} }
R.id.action_new_wg -> { R.id.action_new_wg -> {
startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java)) startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java))
} }
R.id.action_new_shadowtls -> { R.id.action_new_shadowtls -> {
startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java)) startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java))
} }
R.id.action_new_config -> { R.id.action_new_config -> {
startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java)) startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java))
} }
R.id.action_new_chain -> { R.id.action_new_chain -> {
startActivity(Intent(requireActivity(), ChainSettingsActivity::class.java)) startActivity(Intent(requireActivity(), ChainSettingsActivity::class.java))
} }
R.id.action_new_neko -> { R.id.action_new_neko -> {
val context = requireContext() val context = requireContext()
lateinit var dialog: AlertDialog lateinit var dialog: AlertDialog
@ -395,6 +413,7 @@ class ConfigurationFragment @JvmOverloads constructor(
.setView(linearLayout) .setView(linearLayout)
.show() .show()
} }
R.id.action_clear_traffic_statistics -> { R.id.action_clear_traffic_statistics -> {
runOnDefaultDispatcher { runOnDefaultDispatcher {
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId()) val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
@ -411,6 +430,7 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
} }
R.id.action_connection_test_clear_results -> { R.id.action_connection_test_clear_results -> {
runOnDefaultDispatcher { runOnDefaultDispatcher {
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId()) val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
@ -428,6 +448,7 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
} }
R.id.action_connection_test_delete_unavailable -> { R.id.action_connection_test_delete_unavailable -> {
runOnDefaultDispatcher { runOnDefaultDispatcher {
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId()) val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
@ -466,6 +487,7 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
} }
R.id.action_remove_duplicate -> { R.id.action_remove_duplicate -> {
runOnDefaultDispatcher { runOnDefaultDispatcher {
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId()) val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
@ -517,9 +539,11 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
} }
R.id.action_connection_tcp_ping -> { R.id.action_connection_tcp_ping -> {
pingTest(false) pingTest(false)
} }
R.id.action_connection_url_test -> { R.id.action_connection_url_test -> {
urlTest() urlTest()
} }
@ -561,18 +585,22 @@ class ConfigurationFragment @JvmOverloads constructor(
profileStatusText = profile.error profileStatusText = profile.error
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary) profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
} }
0 -> { 0 -> {
profileStatusText = getString(R.string.connection_test_testing) profileStatusText = getString(R.string.connection_test_testing)
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary) profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
} }
1 -> { 1 -> {
profileStatusText = getString(R.string.available, profile.ping) profileStatusText = getString(R.string.available, profile.ping)
profileStatusColor = context.getColour(R.color.material_green_500) profileStatusColor = context.getColour(R.color.material_green_500)
} }
2 -> { 2 -> {
profileStatusText = profile.error profileStatusText = profile.error
profileStatusColor = context.getColour(R.color.material_red_500) profileStatusColor = context.getColour(R.color.material_red_500)
} }
3 -> { 3 -> {
val err = profile.error ?: "" val err = profile.error ?: ""
val msg = Protocols.genFriendlyMsg(err) val msg = Protocols.genFriendlyMsg(err)
@ -705,15 +733,18 @@ class ConfigurationFragment @JvmOverloads constructor(
when { when {
!message.contains("failed:") -> profile.error = !message.contains("failed:") -> profile.error =
getString(R.string.connection_test_timeout) getString(R.string.connection_test_timeout)
else -> when { else -> when {
message.contains("ECONNREFUSED") -> { message.contains("ECONNREFUSED") -> {
profile.error = profile.error =
getString(R.string.connection_test_refused) getString(R.string.connection_test_refused)
} }
message.contains("ENETUNREACH") -> { message.contains("ENETUNREACH") -> {
profile.error = profile.error =
getString(R.string.connection_test_unreachable) getString(R.string.connection_test_unreachable)
} }
else -> { else -> {
profile.status = 3 profile.status = 3
profile.error = message profile.error = message
@ -939,7 +970,7 @@ class ConfigurationFragment @JvmOverloads constructor(
override suspend fun onUpdated(data: TrafficData) = Unit override suspend fun onUpdated(data: TrafficData) = Unit
override suspend fun onUpdated(profile: ProxyEntity) = Unit override suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean) = Unit
override suspend fun onRemoved(groupId: Long, profileId: Long) { override suspend fun onRemoved(groupId: Long, profileId: Long) {
val group = groupList.find { it.id == groupId } ?: return val group = groupList.find { it.id == groupId } ?: return
@ -1034,9 +1065,11 @@ class ConfigurationFragment @JvmOverloads constructor(
GroupOrder.ORIGIN -> { GroupOrder.ORIGIN -> {
origin.isChecked = true origin.isChecked = true
} }
GroupOrder.BY_NAME -> { GroupOrder.BY_NAME -> {
byName.isChecked = true byName.isChecked = true
} }
GroupOrder.BY_DELAY -> { GroupOrder.BY_DELAY -> {
byDelay.isChecked = true byDelay.isChecked = true
} }
@ -1267,7 +1300,7 @@ class ConfigurationFragment @JvmOverloads constructor(
} }
} }
override suspend fun onUpdated(profile: ProxyEntity) { override suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean) {
if (profile.groupId != proxyGroup.id) return if (profile.groupId != proxyGroup.id) return
val index = configurationIdList.indexOf(profile.id) val index = configurationIdList.indexOf(profile.id)
if (index < 0) return if (index < 0) return
@ -1275,9 +1308,21 @@ class ConfigurationFragment @JvmOverloads constructor(
if (::undoManager.isInitialized) { if (::undoManager.isInitialized) {
undoManager.flush() undoManager.flush()
} }
val oldProfile = configurationList[profile.id]
configurationList[profile.id] = profile configurationList[profile.id] = profile
notifyItemChanged(index) notifyItemChanged(index)
//
val oldProfile = configurationList[profile.id]
if (noTraffic && oldProfile != null) {
runOnDefaultDispatcher {
onUpdated(
TrafficData(
id = profile.id,
rx = oldProfile.rx,
tx = oldProfile.tx
)
)
}
}
} }
} }
@ -1333,6 +1378,7 @@ class ConfigurationFragment @JvmOverloads constructor(
newProfiles = newProfiles.sortedBy { it.displayName() } newProfiles = newProfiles.sortedBy { it.displayName() }
} }
GroupOrder.BY_DELAY -> { GroupOrder.BY_DELAY -> {
newProfiles = newProfiles =
newProfiles.sortedBy { if (it.status == 1) it.ping else 114514 } newProfiles.sortedBy { if (it.status == 1) it.ping else 114514 }
@ -1538,6 +1584,7 @@ class ConfigurationFragment @JvmOverloads constructor(
R.id.action_standard_clipboard R.id.action_standard_clipboard
) )
} }
!proxyEntity.haveLink() -> { !proxyEntity.haveLink() -> {
popup.menu.removeItem(R.id.action_group_qr) popup.menu.removeItem(R.id.action_group_qr)
popup.menu.removeItem(R.id.action_group_clipboard) popup.menu.removeItem(R.id.action_group_clipboard)
@ -1589,6 +1636,7 @@ class ConfigurationFragment @JvmOverloads constructor(
R.id.action_universal_clipboard -> export( R.id.action_universal_clipboard -> export(
entity.requireBean().toUniversalLink() entity.requireBean().toUniversalLink()
) )
R.id.action_config_export_clipboard -> export(entity.exportConfig().first) R.id.action_config_export_clipboard -> export(entity.exportConfig().first)
R.id.action_config_export_file -> { R.id.action_config_export_file -> {
val cfg = entity.exportConfig() val cfg = entity.exportConfig()

View File

@ -300,6 +300,7 @@ class MainActivity : ThemedActivity(),
R.id.nav_configuration -> { R.id.nav_configuration -> {
displayFragment(ConfigurationFragment()) displayFragment(ConfigurationFragment())
} }
R.id.nav_group -> displayFragment(GroupFragment()) R.id.nav_group -> displayFragment(GroupFragment())
R.id.nav_route -> displayFragment(RouteFragment()) R.id.nav_route -> displayFragment(RouteFragment())
R.id.nav_settings -> displayFragment(SettingsFragment()) R.id.nav_settings -> displayFragment(SettingsFragment())
@ -310,11 +311,13 @@ class MainActivity : ThemedActivity(),
launchCustomTab("https://matsuridayo.github.io/") launchCustomTab("https://matsuridayo.github.io/")
return false return false
} }
R.id.nav_about -> displayFragment(AboutFragment()) R.id.nav_about -> displayFragment(AboutFragment())
R.id.nav_tuiguang -> { R.id.nav_tuiguang -> {
launchCustomTab("https://matsuricom.github.io/") launchCustomTab("https://matsuricom.github.io/")
return false return false
} }
else -> return false else -> return false
} }
navigation.menu.findItem(id).isChecked = true navigation.menu.findItem(id).isChecked = true
@ -352,6 +355,7 @@ class MainActivity : ThemedActivity(),
ProfileManager.postUpdate(DataStore.currentProfile) ProfileManager.postUpdate(DataStore.currentProfile)
} }
} }
else -> {} else -> {}
} }
} }
@ -412,6 +416,16 @@ class MainActivity : ThemedActivity(),
} }
} }
override fun cbSelectorUpdate(id: Long) {
val old = DataStore.selectedProxy
DataStore.selectedProxy = id
DataStore.currentProfile = id
runOnDefaultDispatcher {
ProfileManager.postUpdate(old, true)
ProfileManager.postUpdate(id, true)
}
}
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) { override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) {
when (key) { when (key) {
Key.SERVICE_MODE -> onBinderDied() Key.SERVICE_MODE -> onBinderDied()
@ -449,6 +463,7 @@ class MainActivity : ThemedActivity(),
binding.drawerLayout.open() binding.drawerLayout.open()
navigation.requestFocus() navigation.requestFocus()
} }
KeyEvent.KEYCODE_DPAD_RIGHT -> { KeyEvent.KEYCODE_DPAD_RIGHT -> {
if (binding.drawerLayout.isOpen) { if (binding.drawerLayout.isOpen) {
binding.drawerLayout.close() binding.drawerLayout.close()

View File

@ -16,7 +16,10 @@ class SwitchActivity : ThemedActivity(R.layout.layout_empty),
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_holder, ConfigurationFragment(true, null, R.string.action_switch)) .replace(
R.id.fragment_holder,
ConfigurationFragment(true, null, R.string.action_switch)
)
.commitAllowingStateLoss() .commitAllowingStateLoss()
} }
@ -24,8 +27,8 @@ class SwitchActivity : ThemedActivity(R.layout.layout_empty),
val old = DataStore.selectedProxy val old = DataStore.selectedProxy
DataStore.selectedProxy = profileId DataStore.selectedProxy = profileId
runOnMainDispatcher { runOnMainDispatcher {
ProfileManager.postUpdate(old) ProfileManager.postUpdate(old, true)
ProfileManager.postUpdate(profileId) ProfileManager.postUpdate(profileId, true)
} }
SagerNet.reloadService() SagerNet.reloadService()
finish() finish()

View File

@ -9,9 +9,9 @@ export PATH=$golang/go/bin:$GOPATH/bin:$PATH
source buildScript/init/env_ndk.sh source buildScript/init/env_ndk.sh
if [[ "$OSTYPE" =~ ^darwin ]]; then if [[ "$OSTYPE" =~ ^darwin ]]; then
export PROJECT=$PWD export SRC_ROOT=$PWD
else else
export PROJECT=$(realpath .) export SRC_ROOT=$(realpath .)
fi fi
DEPS=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin DEPS=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin

View File

@ -0,0 +1,26 @@
#!/bin/bash
set -e
source "buildScript/init/env.sh"
ENV_NB4A=1
source "buildScript/lib/core/get_source_env.sh"
pushd ..
######
## From nekoray/libs/get_source.sh
######
####
if [ ! -d "sing-box-extra" ]; then
git clone --no-checkout https://github.com/MatsuriDayo/sing-box-extra.git
fi
pushd sing-box-extra
git checkout "$COMMIT_SING_BOX_EXTRA"
ENV_SING_BOX_EXTRA=1
source $SRC_ROOT/buildScript/lib/core/get_source_env.sh
NO_ENV=1 ./libs/get_source.sh
popd
popd

View File

@ -0,0 +1,8 @@
if [ ! -z $ENV_NB4A ]; then
export COMMIT_SING_BOX_EXTRA="a4eacbd0e54b6ec0a42096c42b6137a5be91a0bc"
fi
if [ ! -z $ENV_SING_BOX_EXTRA ]; then
source libs/get_source_env.sh
export COMMIT_SING_BOX="91495e813068294aae506fdd769437c41dd8d3a3"
fi

View File

@ -2,6 +2,9 @@
source "buildScript/init/env.sh" source "buildScript/init/env.sh"
# fetch soucre
bash buildScript/lib/core/get_source.sh
[ -f libcore/go.mod ] || exit 1 [ -f libcore/go.mod ] || exit 1
cd libcore cd libcore

View File

@ -4,12 +4,12 @@ go 1.18
require ( require (
github.com/codeclysm/extract v2.2.0+incompatible github.com/codeclysm/extract v2.2.0+incompatible
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1 github.com/matsuridayo/libneko v1.0.0 // replaced
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f github.com/matsuridayo/sing-box-extra v1.0.0 // replaced
github.com/miekg/dns v1.1.53 github.com/miekg/dns v1.1.53
github.com/sagernet/sing v0.2.3 github.com/sagernet/sing v0.2.3
github.com/sagernet/sing-box v1.2.4 github.com/sagernet/sing-box v1.0.0 // replaced
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc github.com/sagernet/sing-dns v1.0.0 // replaced
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
github.com/ulikunitz/xz v0.5.10 github.com/ulikunitz/xz v0.5.10
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105
@ -93,10 +93,10 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
// replace github.com/matsuridayo/libneko => ../../libneko replace github.com/matsuridayo/libneko v1.0.0 => ../../libneko
// replace github.com/matsuridayo/sing-box-extra => ../../sing-box-extra replace github.com/matsuridayo/sing-box-extra v1.0.0 => ../../sing-box-extra
replace github.com/sagernet/sing-dns => github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8 replace github.com/sagernet/sing-box v1.0.0 => ../../sing-box
replace github.com/sagernet/sing-box => github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077 replace github.com/sagernet/sing-dns v1.0.0 => ../../sing-dns

View File

@ -76,14 +76,6 @@ github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1 h1:+FflyEuq2hn++MENFuT1/qFHz0KITKK/F6ZHxs23mrg=
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1/go.mod h1:IRO07Queptz/rGFvEW+3Hmwpx7MCup6WiDs4p5jMt4g=
github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077 h1:k2glJShoEN6l1aBVkxETzlspS9Q+/MEJR9B8z5kirhA=
github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077/go.mod h1:LDW5ZOuWURxSWz+auElryalxCBlGbA0zvsC8XSy8Sp0=
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f h1:x0UjjMoYh5WSDGhIuRkmZUhGoxXnK++wyvuPnURhz6Q=
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f/go.mod h1:NfCwDELPcVFo8rp0d/P7M2OPmegGCGcwF4GSpgZu8Rs=
github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8 h1:eEXScrFlYLiXp2n6G6nnRQVPH81TFF1DGu0xqCFcPHY=
github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY= github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs= github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=

View File

@ -14,6 +14,7 @@ import (
"github.com/matsuridayo/libneko/neko_common" "github.com/matsuridayo/libneko/neko_common"
"github.com/matsuridayo/libneko/neko_log" "github.com/matsuridayo/libneko/neko_log"
"github.com/matsuridayo/sing-box-extra/boxmain" "github.com/matsuridayo/sing-box-extra/boxmain"
"github.com/sagernet/sing-box/nekoutils"
) )
//go:linkname resourcePaths github.com/sagernet/sing-box/constant.resourcePaths //go:linkname resourcePaths github.com/sagernet/sing-box/constant.resourcePaths
@ -62,6 +63,9 @@ func InitCore(process, cachePath, internalAssets, externalAssets string,
neko_log.SetupLog(int(maxLogSizeKb)*1024, filepath.Join(cachePath, "neko.log")) neko_log.SetupLog(int(maxLogSizeKb)*1024, filepath.Join(cachePath, "neko.log"))
boxmain.DisableColor() boxmain.DisableColor()
// nekoutils
nekoutils.Selector_OnProxySelected = iif.Selector_OnProxySelected
// Set up some component // Set up some component
go func() { go func() {
defer device.DeferPanicToError("InitCore-go", func(err error) { log.Println(err) }) defer device.DeferPanicToError("InitCore-go", func(err error) { log.Println(err) })

View File

@ -7,6 +7,7 @@ var useProcfs bool
type NB4AInterface interface { type NB4AInterface interface {
UseOfficialAssets() bool UseOfficialAssets() bool
Selector_OnProxySelected(tag string)
} }
type LocalResolver interface { type LocalResolver interface {

View File

@ -1,2 +0,0 @@
go get github.com/sagernet/sing-box@"$1"
go mod tidy

View File

@ -1,2 +0,0 @@
go get github.com/matsuridayo/sing-box-extra@"$1"
go mod tidy

View File

@ -1,2 +0,0 @@
go get github.com/matsuridayo/libneko@"$1"
go mod tidy