This commit is contained in:
armv9 2025-09-04 11:36:43 +09:00
parent 912de10cc3
commit cddcd84ca6
13 changed files with 53 additions and 39 deletions

View File

@ -113,7 +113,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var remoteDns by configurationStore.string(Key.REMOTE_DNS) { "https://dns.google/dns-query" }
var directDns by configurationStore.string(Key.DIRECT_DNS) { "https://223.5.5.5/dns-query" }
var enableDnsRouting by configurationStore.boolean(Key.ENABLE_DNS_ROUTING) { true }
var enableFakeDns by configurationStore.boolean(Key.ENABLE_FAKEDNS)
var enableFakeDns by configurationStore.boolean(Key.ENABLE_FAKEDNS) { true }
var rulesProvider by configurationStore.stringToInt(Key.RULES_PROVIDER)
var logLevel by configurationStore.stringToInt(Key.LOG_LEVEL)
@ -156,7 +156,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var connectionTestConcurrent by configurationStore.int("connectionTestConcurrent") { 5 }
var alwaysShowAddress by configurationStore.boolean(Key.ALWAYS_SHOW_ADDRESS)
var tunImplementation by configurationStore.stringToInt(Key.TUN_IMPLEMENTATION) { TunImplementation.MIXED }
var tunImplementation by configurationStore.stringToInt(Key.TUN_IMPLEMENTATION) { TunImplementation.GVISOR }
var profileTrafficStatistics by configurationStore.boolean(Key.PROFILE_TRAFFIC_STATISTICS) { true }
var yacdURL by configurationStore.string("yacdURL") { "http://127.0.0.1:9090/ui" }

View File

@ -34,6 +34,7 @@ abstract class SagerDatabase : RoomDatabase() {
SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs()
Room.databaseBuilder(SagerNet.application, SagerDatabase::class.java, Key.DB_PROFILE)
// .addMigrations(*SagerDatabase_Migrations.build())
.setJournalMode(JournalMode.TRUNCATE)
.allowMainThreadQueries()
.enableMultiInstanceInvalidation()
.fallbackToDestructiveMigration()

View File

@ -16,6 +16,7 @@ abstract class PublicDatabase : RoomDatabase() {
val instance by lazy {
SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs()
Room.databaseBuilder(SagerNet.application, PublicDatabase::class.java, Key.DB_PUBLIC)
.setJournalMode(JournalMode.TRUNCATE)
.allowMainThreadQueries()
.enableMultiInstanceInvalidation()
.fallbackToDestructiveMigration()

View File

@ -248,16 +248,19 @@ fun Fragment.needReload() {
fun Fragment.needRestart() {
snackbar(R.string.need_restart).setAction(R.string.apply) {
triggerFullRestart(requireContext())
}.show()
}
fun triggerFullRestart(ctx: Context) {
runOnDefaultDispatcher {
SagerNet.stopService()
val ctx = requireContext()
runOnDefaultDispatcher {
delay(500)
SagerDatabase.instance.close()
PublicDatabase.instance.close()
Executable.killAll(true)
delay(500)
Executable.killAll(true)
runOnMainDispatcher {
ProcessPhoenix.triggerRebirth(ctx, Intent(ctx, MainActivity::class.java))
}
}.show()
}
}
fun Context.getColour(@ColorRes colorRes: Int): Int {

View File

@ -266,6 +266,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
}
}
} catch (e: Exception) {
Logs.w(e)
runOnMainDispatcher {
Toast.makeText(app, e.readableMessage, Toast.LENGTH_SHORT).show()
}

View File

@ -16,6 +16,7 @@ import com.jakewharton.processphoenix.ProcessPhoenix
import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.bg.Executable
import io.nekohasekai.sagernet.database.*
import io.nekohasekai.sagernet.database.preference.KeyValuePair
import io.nekohasekai.sagernet.database.preference.PublicDatabase
@ -65,19 +66,11 @@ class BackupFragment : NamedFragment(R.layout.layout_backup) {
binding.resetSettings.setOnClickListener {
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.confirm)
.setMessage(R.string.reset_settings)
.setMessage(R.string.reset_settings_message)
.setNegativeButton(R.string.no, null)
.setPositiveButton(R.string.yes) { _, _ ->
runOnDefaultDispatcher {
DataStore.configurationStore.reset()
delay(500)
runOnMainDispatcher {
ProcessPhoenix.triggerRebirth(
requireContext(),
Intent(requireContext(), MainActivity::class.java)
)
}
}
DataStore.configurationStore.reset()
triggerFullRestart(requireContext())
}
.show()
}
@ -251,9 +244,7 @@ class BackupFragment : NamedFragment(R.layout.layout_backup) {
import.backupRules.isChecked,
import.backupSettings.isChecked
)
ProcessPhoenix.triggerRebirth(
requireContext(), Intent(requireContext(), MainActivity::class.java)
)
triggerFullRestart(requireContext())
}.onFailure {
Logs.w(it)
onMainDispatcher {

View File

@ -9,9 +9,10 @@ import android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
import android.text.style.ForegroundColorSpan
import android.view.MenuItem
import android.view.View
import android.widget.ScrollView
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat
import androidx.core.view.doOnLayout
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.databinding.LayoutLogcatBinding
import io.nekohasekai.sagernet.ktx.*
@ -41,7 +42,6 @@ class LogcatFragment : ToolbarFragment(R.layout.layout_logcat),
ViewCompat.setOnApplyWindowInsetsListener(binding.root, ListListener)
reloadSession()
// TODO new logcat
}
private fun getColorForLine(line: String): ForegroundColorSpan {
@ -76,8 +76,15 @@ class LogcatFragment : ToolbarFragment(R.layout.layout_logcat),
}
binding.textview.text = span
binding.scroolview.post {
binding.scroolview.fullScroll(ScrollView.FOCUS_DOWN)
// 阻止自动滚动/焦点干扰
binding.scroolview.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS
binding.textview.isFocusable = false
binding.textview.isFocusableInTouchMode = false
binding.textview.clearFocus()
// 等 textview 完成最终 layout 再滚动到底部
binding.textview.doOnLayout {
binding.scroolview.scrollTo(0, binding.textview.height)
}
}

View File

@ -493,4 +493,5 @@
<string name="update_dialog_message">当前版本:%1$s\n可升级版本%2$s\n是否前往下载</string>
<string name="check_update_no">检查成功,但没有更新。</string>
<string name="reset_settings">恢复默认设置</string>
<string name="reset_settings_message">恢复默认设置,但节点、分组等数据将保留。如需完全清除数据,请在系统设置中直接清除应用数据。</string>
</resources>

View File

@ -573,4 +573,5 @@
<string name="update_dialog_message">Current version: %1$s\nAvailable version: %2$s\nDo you want to download it?</string>
<string name="check_update_no">Check successful, but no updates.</string>
<string name="reset_settings">Restore default settings</string>
<string name="reset_settings_message">Restore default settings, but data such as nodes and groups will be retained. To completely clear data, clear application data directly in the system settings.</string>
</resources>

View File

@ -29,7 +29,7 @@
app:title="@string/service_mode"
app:useSimpleSummaryProvider="true" />
<moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="2"
app:defaultValue="0"
app:entries="@array/tun_implementation"
app:entryValues="@array/int_array_3"
app:icon="@drawable/ic_baseline_flip_camera_android_24"
@ -181,6 +181,7 @@
app:summary="@string/dns_routing_message"
app:title="@string/enable_dns_routing" />
<SwitchPreference
app:defaultValue="true"
app:icon="@drawable/ic_action_lock"
app:key="enableFakeDns"
app:summary="@string/fakedns_message"

View File

@ -13,9 +13,11 @@ func GoDebug(any interface{}) {
}
}
func DeferPanicToError(name string, err func(error)) {
func DeferPanicToError(name string, onError func(error)) {
if r := recover(); r != nil {
s := fmt.Errorf("%s panic: %s\n%s", name, r, string(debug.Stack()))
err(s)
if onError != nil {
s := fmt.Errorf("%s panic: %s\n%s", name, r, string(debug.Stack()))
onError(s)
}
}
}

View File

@ -207,6 +207,7 @@ func (r *httpRequest) SetContentString(content string) {
}
func (r *httpRequest) Execute() (HTTPResponse, error) {
defer device.DeferPanicToError("http execute", func(err error) { log.Println(err) })
// full direct
if r.tryH3Direct && !r.trySocks5 {
return r.doH3Direct()
@ -272,7 +273,7 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) {
}
return echClient.Do(request)
},
// H3
// H3 HTTPS
func() (response *http.Response, err error) {
request := r.request.Clone(context.Background())
h3Client := &http.Client{
@ -287,11 +288,13 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) {
},
}
if r.request.URL.Scheme == "http" {
funcs = funcs[:1]
}
for i, f := range funcs {
go func(f requestFunc) {
defer device.DeferPanicToError("http", func(err error) {
log.Println(err)
})
defer device.DeferPanicToError("http", func(err error) { log.Println(err) })
defer func() {
if successCount.Load() == 0 {
if failedCount.Add(1) >= uint32(len(funcs)) {
@ -317,17 +320,19 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) {
mu.Lock()
finalErr = errors.Join(finalErr, fmt.Errorf("%s: %w", t, err))
mu.Unlock()
if rsp != nil && rsp.Body != nil {
rsp.Body.Close()
}
return
}
// 处理 HTTP 状态码
if rsp.StatusCode != http.StatusOK {
hr := &httpResponse{Response: rsp}
err = errors.Join(finalErr, fmt.Errorf("%s: %s", t, hr.errorString()))
err = fmt.Errorf("%s: %s", t, hr.errorString())
mu.Lock()
finalErr = err
finalErr = errors.Join(finalErr, err)
mu.Unlock()
rsp.Body.Close()
return
}

View File

@ -1,4 +1,4 @@
PACKAGE_NAME=moe.nb4a
VERSION_NAME=1.3.9
PRE_VERSION_NAME=pre-1.4.0-20250903-1
PRE_VERSION_NAME=pre-1.4.0-20250904-1
VERSION_CODE=43