1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3use std::fs;
4use std::io;
5use dirs::config_dir;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ProxyConfig {
9 pub enabled: bool,
10 pub url: Option<String>,
11 pub username: Option<String>,
12 pub password: Option<String>,
13 pub proxy_type: ProxyType,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum ProxyType {
18 Http,
19 Https,
20 Socks5,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct OptimizationConfig {
25 pub compression: bool,
26 pub compression_level: u8,
27 pub cache_enabled: bool,
28 pub cache_dir: String,
29 pub speed_limit: Option<u64>,
30 pub max_connections: usize,
31}
32
33fn default_torrent_max_peer_connections() -> u32 {
35 50
36}
37
38fn default_torrent_max_upload_slots() -> u32 {
40 4
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct TorrentConfig {
45 pub enabled: bool,
46 pub download_dir: Option<String>,
47 pub max_peers: usize,
48 pub max_seeds: usize,
49 pub port: Option<u16>,
50 pub dht_enabled: bool,
51 #[serde(default = "default_torrent_max_peer_connections")]
52 pub max_peer_connections: u32,
53 #[serde(default = "default_torrent_max_upload_slots")]
54 pub max_upload_slots: u32,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct FtpConfig {
59 pub passive_mode: bool,
60 pub default_port: u16,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct SftpConfig {
65 pub default_port: u16,
66 pub key_path: Option<String>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Config {
71 pub proxy: ProxyConfig,
72 pub optimization: OptimizationConfig,
73 pub torrent: TorrentConfig,
74 pub ftp: FtpConfig,
75 pub sftp: SftpConfig,
76}
77
78impl Config {
79 pub fn load() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
80 let config_path = Self::get_config_path()?;
81
82 if !config_path.exists() {
83 return Ok(Self::default());
85 }
86
87 let config_str = fs::read_to_string(config_path)?;
88 let config: Config = serde_json::from_str(&config_str)?;
90
91 Ok(config)
92 }
93
94 pub fn save(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
95 let config_path = Self::get_config_path()?;
96
97 if let Some(parent) = config_path.parent() {
99 fs::create_dir_all(parent)?;
100 }
101
102 let config_str = serde_json::to_string_pretty(self)?;
103 fs::write(config_path, config_str)?;
104
105 Ok(())
106 }
107
108 fn get_config_path() -> Result<PathBuf, io::Error> {
109 let mut path = config_dir().ok_or_else(|| {
110 io::Error::new(io::ErrorKind::NotFound, "Not able to find config directory")
111 })?;
112
113 path.push("kget");
114 path.push("config.json");
115
116 Ok(path)
117 }
118}
119
120impl Default for Config {
121 fn default() -> Self {
122 Self {
123 proxy: ProxyConfig {
124 enabled: false,
125 url: None,
126 username: None,
127 password: None,
128 proxy_type: ProxyType::Http,
129 },
130 optimization: OptimizationConfig {
131 compression: true,
132 compression_level: 6,
133 cache_enabled: true,
134 cache_dir: "~/.cache/kget".to_string(),
135 speed_limit: None,
136 max_connections: 4,
137 },
138 torrent: TorrentConfig {
139 enabled: false,
140 download_dir: None,
141 max_peers: 50,
142 max_seeds: 25,
143 port: None,
144 dht_enabled: true,
145 max_peer_connections: default_torrent_max_peer_connections(),
146 max_upload_slots: default_torrent_max_upload_slots(),
147 },
148 ftp: FtpConfig {
149 passive_mode: true,
150 default_port: 21,
151 },
152 sftp: SftpConfig {
153 default_port: 22,
154 key_path: None,
155 },
156 }
157 }
158}