mirror of
https://github.com/simon-ding/polaris.git
synced 2026-06-09 03:27:39 +08:00
feat(ui): add nat traversal option
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"polaris/ent/downloadclients"
|
"polaris/ent/downloadclients"
|
||||||
|
"polaris/log"
|
||||||
"polaris/pkg/nat"
|
"polaris/pkg/nat"
|
||||||
"polaris/pkg/qbittorrent"
|
"polaris/pkg/qbittorrent"
|
||||||
|
|
||||||
@@ -10,31 +12,33 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *Engine) stunProxyDownloadClient() error {
|
func (s *Engine) stunProxyDownloadClient() error {
|
||||||
downloader, e, err := s.GetDownloadClient()
|
downloaders := s.db.GetAllDonloadClients()
|
||||||
if err != nil {
|
for _, d := range downloaders {
|
||||||
return err
|
if !d.Enable {
|
||||||
}
|
continue
|
||||||
if !e.UseNatTraversal {
|
}
|
||||||
return nil
|
|
||||||
}
|
if d.Implementation != downloadclients.ImplementationQbittorrent { //TODO only support qbittorrent for now
|
||||||
if e.Implementation != downloadclients.ImplementationQbittorrent {
|
continue
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
d, ok := downloader.(*qbittorrent.Client)
|
qbt, err := qbittorrent.NewClient(d.URL, d.User, d.Password)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return nil
|
return fmt.Errorf("connect to download client error: %v", d.URL)
|
||||||
}
|
}
|
||||||
u, err := url.Parse(d.URL)
|
u, err := url.Parse(d.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Infof("start stun proxy for %s", d.Name)
|
||||||
|
n, err := nat.NewNatTraversal(func(xa stun.XORMappedAddress) error {
|
||||||
|
return qbt.SetListenPort(xa.Port)
|
||||||
|
}, u.Hostname())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.StartProxy()
|
||||||
|
|
||||||
n, err := nat.NewNatTraversal(func(xa stun.XORMappedAddress) error {
|
|
||||||
return d.SetListenPort(xa.Port)
|
|
||||||
}, u.Hostname())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
n.StartProxy()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ class DownloadClient {
|
|||||||
bool? removeCompletedDownloads;
|
bool? removeCompletedDownloads;
|
||||||
bool? removeFailedDownloads;
|
bool? removeFailedDownloads;
|
||||||
int? priority;
|
int? priority;
|
||||||
|
bool useNatTraversal = false;
|
||||||
DownloadClient(
|
DownloadClient(
|
||||||
{this.id,
|
{this.id,
|
||||||
this.enable,
|
this.enable,
|
||||||
@@ -261,7 +262,7 @@ class DownloadClient {
|
|||||||
this.password,
|
this.password,
|
||||||
this.removeCompletedDownloads = true,
|
this.removeCompletedDownloads = true,
|
||||||
this.priority = 1,
|
this.priority = 1,
|
||||||
this.removeFailedDownloads = true});
|
this.removeFailedDownloads = true, this.useNatTraversal = false});
|
||||||
|
|
||||||
DownloadClient.fromJson(Map<String, dynamic> json) {
|
DownloadClient.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
id = json['id'];
|
||||||
@@ -274,6 +275,7 @@ class DownloadClient {
|
|||||||
priority = json["priority1"];
|
priority = json["priority1"];
|
||||||
removeCompletedDownloads = json["remove_completed_downloads"] ?? false;
|
removeCompletedDownloads = json["remove_completed_downloads"] ?? false;
|
||||||
removeFailedDownloads = json["remove_failed_downloads"] ?? false;
|
removeFailedDownloads = json["remove_failed_downloads"] ?? false;
|
||||||
|
useNatTraversal = json["use_nat_traversal"]?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -288,6 +290,7 @@ class DownloadClient {
|
|||||||
data["priority"] = priority;
|
data["priority"] = priority;
|
||||||
data["remove_completed_downloads"] = removeCompletedDownloads;
|
data["remove_completed_downloads"] = removeCompletedDownloads;
|
||||||
data["remove_failed_downloads"] = removeFailedDownloads;
|
data["remove_failed_downloads"] = removeFailedDownloads;
|
||||||
|
data["use_nat_traversal"] = useNatTraversal;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
|||||||
"remove_completed_downloads": client.removeCompletedDownloads,
|
"remove_completed_downloads": client.removeCompletedDownloads,
|
||||||
"remove_failed_downloads": client.removeFailedDownloads,
|
"remove_failed_downloads": client.removeFailedDownloads,
|
||||||
"priority": client.priority.toString(),
|
"priority": client.priority.toString(),
|
||||||
|
"use_nat_traversal": client.useNatTraversal,
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -86,6 +87,12 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
|||||||
labelText: "优先级", helperText: "1-50, 1最高优先级,50最低优先级"),
|
labelText: "优先级", helperText: "1-50, 1最高优先级,50最低优先级"),
|
||||||
validator: FormBuilderValidators.integer(),
|
validator: FormBuilderValidators.integer(),
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction),
|
autovalidateMode: AutovalidateMode.onUserInteraction),
|
||||||
|
FormBuilderSwitch(
|
||||||
|
name: "use_nat_traversal",
|
||||||
|
enabled: client.implementation == "qbittorrent",
|
||||||
|
title: const Text("使用内置STUN NAT穿透"),
|
||||||
|
decoration: InputDecoration(helperText: "内建的NAT穿透功能帮助BT客户端上传(会自动更改下载器的监听地址)"),
|
||||||
|
),
|
||||||
FormBuilderSwitch(
|
FormBuilderSwitch(
|
||||||
name: "remove_completed_downloads",
|
name: "remove_completed_downloads",
|
||||||
title: const Text("任务完成后删除")),
|
title: const Text("任务完成后删除")),
|
||||||
@@ -150,6 +157,7 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
|||||||
user: _enableAuth ? values["user"] : null,
|
user: _enableAuth ? values["user"] : null,
|
||||||
password: _enableAuth ? values["password"] : null,
|
password: _enableAuth ? values["password"] : null,
|
||||||
priority: int.parse(values["priority"]),
|
priority: int.parse(values["priority"]),
|
||||||
|
useNatTraversal: values["use_nat_traversal"],
|
||||||
removeCompletedDownloads: values["remove_completed_downloads"],
|
removeCompletedDownloads: values["remove_completed_downloads"],
|
||||||
removeFailedDownloads: values["remove_failed_downloads"]));
|
removeFailedDownloads: values["remove_failed_downloads"]));
|
||||||
} else {
|
} else {
|
||||||
@@ -165,7 +173,12 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return showSettingDialog(
|
return showSettingDialog(
|
||||||
context, title, client.idExists() && client.implementation != "buildin", body, onSubmit, onDelete);
|
context,
|
||||||
|
title,
|
||||||
|
client.idExists() && client.implementation != "buildin",
|
||||||
|
body,
|
||||||
|
onSubmit,
|
||||||
|
onDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showSelections() {
|
Future<void> showSelections() {
|
||||||
|
|||||||
Reference in New Issue
Block a user