diff --git a/internal/protocol/bt/config.go b/internal/protocol/bt/config.go index fdbbedaf..e9d2a238 100644 --- a/internal/protocol/bt/config.go +++ b/internal/protocol/bt/config.go @@ -9,4 +9,8 @@ type config struct { SeedRatio float64 `json:"seedRatio"` // SeedTime is the time in seconds to seed after downloading is complete. SeedTime int64 `json:"seedTime"` + // DisableDHT and DisablePEX turn off DHT and PEX peer discovery. Like ListenPort, + // they are read when the shared client is built. + DisableDHT bool `json:"disableDht"` + DisablePEX bool `json:"disablePex"` } diff --git a/internal/protocol/bt/fetcher.go b/internal/protocol/bt/fetcher.go index 73b5175b..e22c403a 100644 --- a/internal/protocol/bt/fetcher.go +++ b/internal/protocol/bt/fetcher.go @@ -77,6 +77,8 @@ func (f *Fetcher) initClient() (err error) { cfg.Bep20 = fmt.Sprintf("-GP%s-", parseBep20()) cfg.ExtendedHandshakeClientVersion = fmt.Sprintf("Gopeed %s", base.Version) cfg.ListenPort = f.config.ListenPort + cfg.NoDHT = f.config.DisableDHT + cfg.DisablePEX = f.config.DisablePEX cfg.HTTPProxy = f.ctl.GetProxy(f.meta.Req.Proxy) dnsResolver := &DnsCacheResolver{RefreshTimeout: 5 * time.Minute} cfg.TrackerDialContext = dnsResolver.DialContext @@ -839,6 +841,8 @@ func (fm *FetcherManager) DefaultConfig() any { SeedKeep: false, SeedRatio: 1.0, SeedTime: 120 * 60, + DisableDHT: false, + DisablePEX: false, } } diff --git a/internal/protocol/bt/fetcher_test.go b/internal/protocol/bt/fetcher_test.go index ad823d83..b13e38ed 100644 --- a/internal/protocol/bt/fetcher_test.go +++ b/internal/protocol/bt/fetcher_test.go @@ -366,3 +366,52 @@ func TestFetcher_Patch(t *testing.T) { } }) } + +func TestFetcher_PeerDiscoveryConfig(t *testing.T) { + tests := []struct { + name string + stored any + wantDisableDHT bool + wantDisablePEX bool + }{ + {"default config", new(FetcherManager).DefaultConfig(), false, false}, + {"stored config without the fields", map[string]any{"listenPort": 0, "seedRatio": 1.0}, false, false}, + {"both disabled", map[string]any{"disableDht": true, "disablePex": true}, true, true}, + {"only DHT disabled", map[string]any{"disableDht": true}, true, false}, + {"only PEX disabled", map[string]any{"disablePex": true}, false, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := buildFetcherWithConfig(tt.stored).(*Fetcher) + if f.config.DisableDHT != tt.wantDisableDHT || f.config.DisablePEX != tt.wantDisablePEX { + t.Errorf("config got DisableDHT = %v, DisablePEX = %v, want %v, %v", f.config.DisableDHT, f.config.DisablePEX, tt.wantDisableDHT, tt.wantDisablePEX) + } + }) + } +} + +func TestFetcher_PeerDiscoveryDisabledOnClient(t *testing.T) { + if err := closeClient(); err != nil { + t.Fatal(err) + } + f := buildFetcherWithConfig(map[string]any{"disableDht": true, "disablePex": true}) + if err := f.Resolve(&base.Request{URL: "./testdata/test.torrent"}, nil); err != nil { + t.Fatal(err) + } + if !cfg.NoDHT || !cfg.DisablePEX { + t.Errorf("client config got NoDHT = %v, DisablePEX = %v, want true", cfg.NoDHT, cfg.DisablePEX) + } + if n := len(client.DhtServers()); n != 0 { + t.Errorf("client got %d DHT servers, want 0", n) + } +} + +func buildFetcherWithConfig(stored any) fetcher.Fetcher { + fetcher := new(FetcherManager).Build() + newController := controller.NewController() + newController.GetConfig = func(v any) { + json.Unmarshal([]byte(test.ToJson(stored)), v) + } + fetcher.Setup(newController) + return fetcher +} diff --git a/ui/flutter/lib/api/model/downloader_config.dart b/ui/flutter/lib/api/model/downloader_config.dart index dae6a103..a1503953 100644 --- a/ui/flutter/lib/api/model/downloader_config.dart +++ b/ui/flutter/lib/api/model/downloader_config.dart @@ -105,6 +105,8 @@ class BtConfig { bool seedKeep; double seedRatio; int seedTime; + bool disableDht; + bool disablePex; BtConfig({ this.listenPort = 0, @@ -112,6 +114,8 @@ class BtConfig { this.seedKeep = false, this.seedRatio = 0, this.seedTime = 0, + this.disableDht = false, + this.disablePex = false, }); factory BtConfig.fromJson(Map json) => _$BtConfigFromJson(json); diff --git a/ui/flutter/lib/api/model/downloader_config.g.dart b/ui/flutter/lib/api/model/downloader_config.g.dart index 2ee3c2d8..63a3a248 100644 --- a/ui/flutter/lib/api/model/downloader_config.g.dart +++ b/ui/flutter/lib/api/model/downloader_config.g.dart @@ -98,6 +98,8 @@ BtConfig _$BtConfigFromJson(Map json) => BtConfig( seedKeep: json['seedKeep'] as bool? ?? false, seedRatio: (json['seedRatio'] as num?)?.toDouble() ?? 0, seedTime: (json['seedTime'] as num?)?.toInt() ?? 0, + disableDht: json['disableDht'] as bool? ?? false, + disablePex: json['disablePex'] as bool? ?? false, ); Map _$BtConfigToJson(BtConfig instance) => { @@ -106,6 +108,8 @@ Map _$BtConfigToJson(BtConfig instance) => { 'seedKeep': instance.seedKeep, 'seedRatio': instance.seedRatio, 'seedTime': instance.seedTime, + 'disableDht': instance.disableDht, + 'disablePex': instance.disablePex, }; Ed2kConfig _$Ed2kConfigFromJson(Map json) => Ed2kConfig( diff --git a/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart b/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart index eb105959..d3ca1301 100644 --- a/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart +++ b/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart @@ -623,6 +623,22 @@ class _SettingsPageState extends ConsumerState { max: 65535, ), ), + SettingsItem( + title: context.l10n.enableDht, + subtitle: context.l10n.restartRequired, + child: shad.Switch( + value: !config.protocolConfig.bt.disableDht, + onChanged: (value) => _mutateConfig((next) => next.protocolConfig.bt.disableDht = !value), + ), + ), + SettingsItem( + title: context.l10n.enablePex, + subtitle: context.l10n.restartRequired, + child: shad.Switch( + value: !config.protocolConfig.bt.disablePex, + onChanged: (value) => _mutateConfig((next) => next.protocolConfig.bt.disablePex = !value), + ), + ), SettingsItem( title: context.l10n.seedKeep, child: shad.Switch( diff --git a/ui/flutter/lib/l10n/app_ar.arb b/ui/flutter/lib/l10n/app_ar.arb index 105be8c0..8ad2315f 100644 --- a/ui/flutter/lib/l10n/app_ar.arb +++ b/ui/flutter/lib/l10n/app_ar.arb @@ -154,6 +154,8 @@ "seedKeep": "الاستمرار في المشاركة حتى الإيقاف اليدوي", "seedRatio": "نسبة المشاركة", "seedTime": "مدة المشاركة (دقائق)", + "enableDht": "تفعيل DHT", + "enablePex": "تفعيل PEX", "setAsDefaultBtClient": "تعيين كعميل تورنت افتراضي", "taskDetail": "تفاصيل المهمة", "taskName": "اسم المهمة", diff --git a/ui/flutter/lib/l10n/app_az.arb b/ui/flutter/lib/l10n/app_az.arb index 84fb90e7..2e20e587 100644 --- a/ui/flutter/lib/l10n/app_az.arb +++ b/ui/flutter/lib/l10n/app_az.arb @@ -161,6 +161,8 @@ "seedKeep": "Əl ilə dayandırılana qədər seed etməyə davam et", "seedRatio": "Seed nisbəti", "seedTime": "Seed müddəti (dəqiqə)", + "enableDht": "DHT-ni aktivləşdir", + "enablePex": "PEX-i aktivləşdir", "setAsDefaultBtClient": "Standart BT müştərisi kimi təyin et", "taskDetail": "Tapşırıq Detalları", "taskName": "Tapşırığın Adı", diff --git a/ui/flutter/lib/l10n/app_ca.arb b/ui/flutter/lib/l10n/app_ca.arb index f8bdbce6..9c6824d1 100644 --- a/ui/flutter/lib/l10n/app_ca.arb +++ b/ui/flutter/lib/l10n/app_ca.arb @@ -154,6 +154,8 @@ "seedKeep": "Continua sembrant fins que s'aturi manualment", "seedRatio": "Proporció de les llavors", "seedTime": "Temps de la llavor (minuts)", + "enableDht": "Activa DHT", + "enablePex": "Activa PEX", "setAsDefaultBtClient": "Estableix com a client BT per defecte", "taskDetail": "Detall de la tasca", "taskName": "Nom de la tasca", diff --git a/ui/flutter/lib/l10n/app_de.arb b/ui/flutter/lib/l10n/app_de.arb index 063e7cb6..d7437017 100644 --- a/ui/flutter/lib/l10n/app_de.arb +++ b/ui/flutter/lib/l10n/app_de.arb @@ -154,6 +154,8 @@ "seedKeep": "Weiter-seeden bis manuell gestoppt", "seedRatio": "Seed Verhältniss", "seedTime": "Seed-Zeit (Minuten)", + "enableDht": "DHT aktivieren", + "enablePex": "PEX aktivieren", "setAsDefaultBtClient": "Als Standard-BT-Client festlegen", "taskDetail": "Aufgabendetails", "taskName": "Aufgabenname", diff --git a/ui/flutter/lib/l10n/app_en.arb b/ui/flutter/lib/l10n/app_en.arb index 2fda6b77..ae3c56d1 100644 --- a/ui/flutter/lib/l10n/app_en.arb +++ b/ui/flutter/lib/l10n/app_en.arb @@ -168,6 +168,8 @@ "seedKeep": "Keep seeding until manually stopped", "seedRatio": "Seed ratio", "seedTime": "Seed time (minutes)", + "enableDht": "Enable DHT", + "enablePex": "Enable PEX", "setAsDefaultBtClient": "Set as the default BT client", "taskDetail": "Task Detail", "taskName": "Task Name", diff --git a/ui/flutter/lib/l10n/app_es.arb b/ui/flutter/lib/l10n/app_es.arb index 6f2eeade..e9f3dfb4 100644 --- a/ui/flutter/lib/l10n/app_es.arb +++ b/ui/flutter/lib/l10n/app_es.arb @@ -154,6 +154,8 @@ "seedKeep": "Mantener sembrado", "seedRatio": "Ratio de semilla", "seedTime": "Tiempo de semilla (minutos)", + "enableDht": "Activar DHT", + "enablePex": "Activar PEX", "setAsDefaultBtClient": "Establecer como el cliente BT predeterminado", "taskDetail": "Detalles de la Tarea", "taskName": "Nombre de la Tarea", diff --git a/ui/flutter/lib/l10n/app_fa.arb b/ui/flutter/lib/l10n/app_fa.arb index 9d0444ea..b47757d3 100644 --- a/ui/flutter/lib/l10n/app_fa.arb +++ b/ui/flutter/lib/l10n/app_fa.arb @@ -154,6 +154,8 @@ "seedKeep": "بذر را نگه دارید تا زمانی که به صورت دستی متوقف شود", "seedRatio": "نسبت دید", "seedTime": "زمان ( دقیقه)", + "enableDht": "فعال‌سازی DHT", + "enablePex": "فعال‌سازی PEX", "setAsDefaultBtClient": "تنظیم به‌عنوان کلاینت پیش‌فرض BT", "taskDetail": "جزئیات وظیفه", "taskName": "نام وظیفه", diff --git a/ui/flutter/lib/l10n/app_fr.arb b/ui/flutter/lib/l10n/app_fr.arb index 101cb5a9..efca9e9f 100644 --- a/ui/flutter/lib/l10n/app_fr.arb +++ b/ui/flutter/lib/l10n/app_fr.arb @@ -154,6 +154,8 @@ "seedKeep": "Continuer à semer jusqu'à ce qu'il soit arrêté manuellement", "seedRatio": "Taux de semences", "seedTime": "Temps de semis (minutes)", + "enableDht": "Activer DHT", + "enablePex": "Activer PEX", "setAsDefaultBtClient": "Définir comme le client BT par défaut", "taskDetail": "Détail de la tâche", "taskName": "Nom de la tâche", diff --git a/ui/flutter/lib/l10n/app_hu.arb b/ui/flutter/lib/l10n/app_hu.arb index d96afc27..a5280139 100644 --- a/ui/flutter/lib/l10n/app_hu.arb +++ b/ui/flutter/lib/l10n/app_hu.arb @@ -154,6 +154,8 @@ "seedKeep": "Tartsa a seedet amíg manuálisan le nem állítják", "seedRatio": "Seed arány", "seedTime": "Seed idő (perc)", + "enableDht": "DHT engedélyezése", + "enablePex": "PEX engedélyezése", "setAsDefaultBtClient": "Alapértelmezett BT klienseként beállít", "taskDetail": "Feladat részlete", "taskName": "Feladat neve", diff --git a/ui/flutter/lib/l10n/app_id.arb b/ui/flutter/lib/l10n/app_id.arb index 91a47d6f..f334f2e3 100644 --- a/ui/flutter/lib/l10n/app_id.arb +++ b/ui/flutter/lib/l10n/app_id.arb @@ -154,6 +154,8 @@ "seedKeep": "Terus seeding hingga dihentikan secara manual", "seedRatio": "Rasio Seed", "seedTime": "Waktu Seed (menit)", + "enableDht": "Aktifkan DHT", + "enablePex": "Aktifkan PEX", "setAsDefaultBtClient": "Atur sebagai klien baku BT", "taskDetail": "Detail Tugas", "taskName": "Nama Tugas", diff --git a/ui/flutter/lib/l10n/app_it.arb b/ui/flutter/lib/l10n/app_it.arb index 15a510bb..7d140ee8 100644 --- a/ui/flutter/lib/l10n/app_it.arb +++ b/ui/flutter/lib/l10n/app_it.arb @@ -154,6 +154,8 @@ "seedKeep": "Continuare a vedere fino a quando non è stato interrotto manualmente", "seedRatio": "Rapporto di taglio", "seedTime": "Tempo di seme (minuti)", + "enableDht": "Abilita DHT", + "enablePex": "Abilita PEX", "setAsDefaultBtClient": "Impostare come client BT predefinito", "taskDetail": "Dettaglio delle attività", "taskName": "Nome della missione", diff --git a/ui/flutter/lib/l10n/app_ja.arb b/ui/flutter/lib/l10n/app_ja.arb index e7dec4be..9928f2ce 100644 --- a/ui/flutter/lib/l10n/app_ja.arb +++ b/ui/flutter/lib/l10n/app_ja.arb @@ -154,6 +154,8 @@ "seedKeep": "手動で停止するまでシードを継続する", "seedRatio": "シード共有比", "seedTime": "シード時間 (分)", + "enableDht": "DHT を有効にする", + "enablePex": "PEX を有効にする", "setAsDefaultBtClient": "デフォルトのBTクライアントとして設定", "taskDetail": "タスク詳細", "taskName": "タスク名", diff --git a/ui/flutter/lib/l10n/app_ko.arb b/ui/flutter/lib/l10n/app_ko.arb index d51d9f55..9c42a7e5 100644 --- a/ui/flutter/lib/l10n/app_ko.arb +++ b/ui/flutter/lib/l10n/app_ko.arb @@ -154,6 +154,8 @@ "seedKeep": "수동으로 중지할 때까지 계속 시드", "seedRatio": "시드 비율", "seedTime": "시드 시간(분)", + "enableDht": "DHT 사용", + "enablePex": "PEX 사용", "setAsDefaultBtClient": "기본 BT 클라이언트로 설정", "taskDetail": "작업 상세 정보", "taskName": "작업 이름", diff --git a/ui/flutter/lib/l10n/app_pl.arb b/ui/flutter/lib/l10n/app_pl.arb index 95ff16b2..dafd8aa9 100644 --- a/ui/flutter/lib/l10n/app_pl.arb +++ b/ui/flutter/lib/l10n/app_pl.arb @@ -154,6 +154,8 @@ "seedKeep": "Siew siewny do momentu ręcznego zatrzymania", "seedRatio": "Stosunek materiału siewnego", "seedTime": "Czas nasadzenia (minuty)", + "enableDht": "Włącz DHT", + "enablePex": "Włącz PEX", "setAsDefaultBtClient": "Ustaw jako domyślny klient BT", "taskDetail": "Szczegóły zadania", "taskName": "Nazwa zadania", diff --git a/ui/flutter/lib/l10n/app_pt.arb b/ui/flutter/lib/l10n/app_pt.arb index cc869731..572f088a 100644 --- a/ui/flutter/lib/l10n/app_pt.arb +++ b/ui/flutter/lib/l10n/app_pt.arb @@ -154,6 +154,8 @@ "seedKeep": "Manter a semeadura até parar manualmente", "seedRatio": "Relação entre sementes", "seedTime": "Tempo de semente (minutos)", + "enableDht": "Ativar DHT", + "enablePex": "Ativar PEX", "setAsDefaultBtClient": "Definir como o cliente BT padrão", "taskDetail": "Detalhes da Tarefa", "taskName": "Nome da Tarefa", diff --git a/ui/flutter/lib/l10n/app_ru.arb b/ui/flutter/lib/l10n/app_ru.arb index 69b9b08a..5a6bf19c 100644 --- a/ui/flutter/lib/l10n/app_ru.arb +++ b/ui/flutter/lib/l10n/app_ru.arb @@ -154,6 +154,8 @@ "seedKeep": "Раздавать пока не остановлю вручную", "seedRatio": "Коэффициент раздачи", "seedTime": "Время раздачи (минуты)", + "enableDht": "Включить DHT", + "enablePex": "Включить PEX", "setAsDefaultBtClient": "Установить как клиент BT по умолчанию", "taskDetail": "Детали задания", "taskName": "Название задачи", diff --git a/ui/flutter/lib/l10n/app_sk.arb b/ui/flutter/lib/l10n/app_sk.arb index 3097a7be..a28e80c3 100644 --- a/ui/flutter/lib/l10n/app_sk.arb +++ b/ui/flutter/lib/l10n/app_sk.arb @@ -168,6 +168,8 @@ "seedKeep": "Pokračovať v seedovaní až do manuálneho zastavenia", "seedRatio": "Pomer seedovania", "seedTime": "Čas seedovania (minúty)", + "enableDht": "Povoliť DHT", + "enablePex": "Povoliť PEX", "setAsDefaultBtClient": "Nastaviť ako predvoleného BT klienta", "taskDetail": "Detail úlohy", "taskName": "Názov úlohy", diff --git a/ui/flutter/lib/l10n/app_ta.arb b/ui/flutter/lib/l10n/app_ta.arb index d54ccfd2..c48ff6a4 100644 --- a/ui/flutter/lib/l10n/app_ta.arb +++ b/ui/flutter/lib/l10n/app_ta.arb @@ -154,6 +154,8 @@ "seedKeep": "கைமுறையாக நிறுத்தப்படும் வரை விதைப்பதைத் தொடரவும்", "seedRatio": "விதை விகிதம்", "seedTime": "விதை நேரம் (நிமிடங்கள்)", + "enableDht": "DHT ஐ இயக்கு", + "enablePex": "PEX ஐ இயக்கு", "setAsDefaultBtClient": "இயல்புநிலை BT கிளையண்டாக அமைக்கவும்", "taskDetail": "பணி விவரம்", "taskName": "செயல் பெயர்", diff --git a/ui/flutter/lib/l10n/app_tr.arb b/ui/flutter/lib/l10n/app_tr.arb index 32b98445..67253dbd 100644 --- a/ui/flutter/lib/l10n/app_tr.arb +++ b/ui/flutter/lib/l10n/app_tr.arb @@ -154,6 +154,8 @@ "seedKeep": "Manuel olarak durdurulana kadar seed'e devam et", "seedRatio": "Seed oranı", "seedTime": "Seed süresi (dakika)", + "enableDht": "DHT'yi etkinleştir", + "enablePex": "PEX'i etkinleştir", "setAsDefaultBtClient": "Varsayılan BitTorrent istemcisi olarak ayarla", "taskDetail": "İşlem Detayı", "taskName": "İşlem Adı", diff --git a/ui/flutter/lib/l10n/app_uk.arb b/ui/flutter/lib/l10n/app_uk.arb index c27005f0..20fb2caf 100644 --- a/ui/flutter/lib/l10n/app_uk.arb +++ b/ui/flutter/lib/l10n/app_uk.arb @@ -154,6 +154,8 @@ "seedKeep": "Роздавати доки не зупиню вручну", "seedRatio": "Коефіцієнт роздачі", "seedTime": "Час роздачі (хвилини)", + "enableDht": "Увімкнути DHT", + "enablePex": "Увімкнути PEX", "setAsDefaultBtClient": "Встановити як клієнт BT за замовчуванням", "taskDetail": "Деталі завдання", "taskName": "Назва завдання", diff --git a/ui/flutter/lib/l10n/app_vi.arb b/ui/flutter/lib/l10n/app_vi.arb index ba30e032..68c04c25 100644 --- a/ui/flutter/lib/l10n/app_vi.arb +++ b/ui/flutter/lib/l10n/app_vi.arb @@ -154,6 +154,8 @@ "seedKeep": "Giữ hạt giống cho đến khi tay dừng lại", "seedRatio": "Tốc độ Hạt giống", "seedTime": "Thời gian hạt giống ( Phút)", + "enableDht": "Bật DHT", + "enablePex": "Bật PEX", "setAsDefaultBtClient": "Đặt là trình khách BT mặc định", "taskDetail": "Chi tiết tác vụ", "taskName": "Tên tác vụ", diff --git a/ui/flutter/lib/l10n/app_zh.arb b/ui/flutter/lib/l10n/app_zh.arb index cf1bdf67..19f54a05 100644 --- a/ui/flutter/lib/l10n/app_zh.arb +++ b/ui/flutter/lib/l10n/app_zh.arb @@ -154,6 +154,8 @@ "seedKeep": "持续做种直到手动停止", "seedRatio": "做种分享率", "seedTime": "做种时间(分钟)", + "enableDht": "启用 DHT", + "enablePex": "启用 PEX", "setAsDefaultBtClient": "设为系统默认 BT 客户端", "taskDetail": "任务详情", "taskName": "任务名称", diff --git a/ui/flutter/lib/l10n/app_zh_TW.arb b/ui/flutter/lib/l10n/app_zh_TW.arb index 38444e8b..f3b59ca9 100644 --- a/ui/flutter/lib/l10n/app_zh_TW.arb +++ b/ui/flutter/lib/l10n/app_zh_TW.arb @@ -154,6 +154,8 @@ "seedKeep": "持續做種直到手動停止", "seedRatio": "做種分享率", "seedTime": "做種時間(分鐘)", + "enableDht": "啟用 DHT", + "enablePex": "啟用 PEX", "setAsDefaultBtClient": "設為系統預設 BT 客戶端", "taskDetail": "任務詳情", "taskName": "任務名稱", diff --git a/ui/flutter/test/api/downloader_config_test.dart b/ui/flutter/test/api/downloader_config_test.dart index aa9825d1..5d5f3a49 100644 --- a/ui/flutter/test/api/downloader_config_test.dart +++ b/ui/flutter/test/api/downloader_config_test.dart @@ -36,6 +36,28 @@ void main() { expect(decoded.token, 'secret'); }); + test('BitTorrent peer discovery settings round-trip with the Go json keys', () { + final config = DownloaderConfig(); + config.protocolConfig.bt + ..disableDht = true + ..disablePex = true; + + final json = config.toJson(); + final bt = (json['protocolConfig'] as Map)['bt'] as Map; + expect(bt['disableDht'], isTrue); + expect(bt['disablePex'], isTrue); + + final decoded = DownloaderConfig.fromJson(json).protocolConfig.bt; + expect(decoded.disableDht, isTrue); + expect(decoded.disablePex, isTrue); + }); + + test('BitTorrent peer discovery stays on when a stored config lacks the keys', () { + final bt = BtConfig.fromJson({'listenPort': 6881, 'seedRatio': 1.0}); + expect(bt.disableDht, isFalse); + expect(bt.disablePex, isFalse); + }); + test('Flutter preferences round-trip through the Go-owned extra config', () { final config = DownloaderConfig(); config.extra