ddns 4.1.0b1__py2.py3-none-any.whl → 4.1.0b3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ddns might be problematic. Click here for more details.

ddns/util/config.py DELETED
@@ -1,314 +0,0 @@
1
- # -*- coding:utf-8 -*-
2
- from argparse import Action, ArgumentParser, Namespace, RawTextHelpFormatter
3
- from json import load as loadjson, dump as dumpjson
4
- from os import stat, environ, path
5
- from logging import critical, error, getLevelName
6
- from ast import literal_eval
7
-
8
- import platform
9
- import sys
10
-
11
-
12
- __cli_args = Namespace()
13
- __config = {} # type: dict
14
- log_levels = [
15
- "CRITICAL", # 50
16
- "ERROR", # 40
17
- "WARNING", # 30
18
- "INFO", # 20
19
- "DEBUG", # 10
20
- "NOTSET", # 0
21
- ]
22
-
23
- # 支持数组的参数列表
24
- ARRAY_PARAMS = ["index4", "index6", "ipv4", "ipv6", "proxy"]
25
- # 简单数组,支持’,’, ‘;’ 分隔的参数列表
26
- SIMPLE_ARRAY_PARAMS = ["ipv4", "ipv6", "proxy"]
27
-
28
-
29
- def str2bool(v):
30
- """
31
- parse string to boolean
32
- """
33
- if isinstance(v, bool):
34
- return v
35
- if v.lower() in ("yes", "true", "t", "y", "1"):
36
- return True
37
- elif v.lower() in ("no", "false", "f", "n", "0"):
38
- return False
39
- else:
40
- return v
41
-
42
-
43
- def log_level(value):
44
- """
45
- parse string to log level
46
- or getattr(logging, value.upper())
47
- """
48
- return getLevelName(value.upper())
49
-
50
-
51
- def parse_array_string(value, enable_simple_split):
52
- """
53
- 解析数组字符串
54
- 仅当 trim 之后以 '[' 开头以 ']' 结尾时,才尝试使用 ast.literal_eval 解析
55
- 默认返回原始字符串
56
- """
57
- if not hasattr(value, "strip"): # 非字符串
58
- return value
59
-
60
- trimmed = value.strip()
61
- if trimmed.startswith("[") and trimmed.endswith("]"):
62
- try:
63
- # 尝试使用 ast.literal_eval 解析数组
64
- parsed_value = literal_eval(trimmed)
65
- # 确保解析结果是列表或元组
66
- if isinstance(parsed_value, (list, tuple)):
67
- return list(parsed_value)
68
- except (ValueError, SyntaxError) as e:
69
- # 解析失败时返回原始字符串
70
- error("Failed to parse array string: %s. Exception: %s", value, e)
71
- elif enable_simple_split:
72
- # 尝试使用逗号或分号分隔符解析
73
- sep = None
74
- if "," in trimmed:
75
- sep = ","
76
- elif ";" in trimmed:
77
- sep = ";"
78
- if sep:
79
- return [item.strip() for item in trimmed.split(sep) if item.strip()]
80
- return value
81
-
82
-
83
- def get_system_info_str():
84
- system = platform.system()
85
- release = platform.release()
86
- machine = platform.machine()
87
- arch = platform.architecture()
88
- return "{}-{} {} {}".format(system, release, machine, arch)
89
-
90
-
91
- def get_python_info_str():
92
- version = platform.python_version()
93
- branch, py_build_date = platform.python_build()
94
- return "Python-{} {} ({})".format(version, branch, py_build_date)
95
-
96
-
97
- def init_config(description, doc, version, date):
98
- """
99
- 配置
100
- """
101
- global __cli_args
102
- parser = ArgumentParser(description=description, epilog=doc, formatter_class=RawTextHelpFormatter)
103
- sysinfo = get_system_info_str()
104
- pyinfo = get_python_info_str()
105
- version_str = "v{} ({})\n{}\n{}".format(version, date, pyinfo, sysinfo)
106
- parser.add_argument("-v", "--version", action="version", version=version_str)
107
- parser.add_argument("-c", "--config", metavar="FILE", help="load config file [配置文件路径]")
108
- parser.add_argument("--debug", action="store_true", help="debug mode [开启调试模式]")
109
-
110
- # 参数定义
111
- parser.add_argument(
112
- "--dns",
113
- help="DNS provider [DNS服务提供商]",
114
- choices=[
115
- "alidns",
116
- "cloudflare",
117
- "dnscom",
118
- "dnspod",
119
- "dnspod_com",
120
- "he",
121
- "huaweidns",
122
- "callback",
123
- "debug",
124
- ],
125
- )
126
- parser.add_argument("--id", help="API ID or email [对应账号ID或邮箱]")
127
- parser.add_argument("--token", help="API token or key [授权凭证或密钥]")
128
- parser.add_argument(
129
- "--index4",
130
- nargs="*",
131
- action=ExtendAction,
132
- metavar="RULE",
133
- help="IPv4 rules [获取IPv4方式, 多次可配置多规则]",
134
- )
135
- parser.add_argument(
136
- "--index6",
137
- nargs="*",
138
- action=ExtendAction,
139
- metavar="RULE",
140
- help="IPv6 rules [获取IPv6方式, 多次可配置多规则]",
141
- )
142
- parser.add_argument(
143
- "--ipv4",
144
- nargs="*",
145
- action=ExtendAction,
146
- metavar="DOMAIN",
147
- help="IPv4 domains [IPv4域名列表, 可配置多个域名]",
148
- )
149
- parser.add_argument(
150
- "--ipv6",
151
- nargs="*",
152
- action=ExtendAction,
153
- metavar="DOMAIN",
154
- help="IPv6 domains [IPv6域名列表, 可配置多个域名]",
155
- )
156
- parser.add_argument("--ttl", type=int, help="DNS TTL(s) [设置域名解析过期时间]")
157
- parser.add_argument("--line", help="DNS line/route [DNS线路设置,如电信、联通、移动等]")
158
- parser.add_argument(
159
- "--proxy",
160
- nargs="*",
161
- action=ExtendAction,
162
- help="HTTP proxy [设置http代理,可配多个代理连接]",
163
- )
164
- parser.add_argument(
165
- "--cache",
166
- type=str2bool,
167
- nargs="?",
168
- const=True,
169
- help="set cache [启用缓存开关,或传入保存路径]",
170
- )
171
- parser.add_argument(
172
- "--no-cache",
173
- dest="cache",
174
- action="store_const",
175
- const=False,
176
- help="disable cache [关闭缓存等效 --cache=false]",
177
- )
178
- parser.add_argument(
179
- "--ssl",
180
- help="SSL certificate verification [SSL证书验证方式]: "
181
- "true(强制验证), false(禁用验证), auto(自动降级), /path/to/cert.pem(自定义证书)",
182
- )
183
- parser.add_argument("--log.file", metavar="FILE", help="log file [日志文件,默认标准输出]")
184
- parser.add_argument("--log.level", type=log_level, metavar="|".join(log_levels))
185
- parser.add_argument("--log.format", metavar="FORMAT", help="log format [设置日志打印格式]")
186
- parser.add_argument("--log.datefmt", metavar="FORMAT", help="date format [日志时间打印格式]")
187
-
188
- __cli_args = parser.parse_args()
189
- is_debug = getattr(__cli_args, "debug", False)
190
- if is_debug:
191
- # 如果启用调试模式,则强制设置日志级别为 DEBUG
192
- setattr(__cli_args, "log.level", log_level("DEBUG"))
193
- if not hasattr(__cli_args, "cache"):
194
- setattr(__cli_args, "cache", False) # 禁用缓存
195
-
196
- config_required = not get_config("token") and not get_config("id")
197
- config_file = get_config("config") # type: str | None # type: ignore
198
- if not config_file:
199
- # 未指定配置文件且需要读取文件时,依次查找
200
- cfgs = [
201
- path.abspath("config.json"),
202
- path.expanduser("~/.ddns/config.json"),
203
- "/etc/ddns/config.json",
204
- ]
205
- config_file = next((cfg for cfg in cfgs if path.isfile(cfg)), cfgs[0])
206
-
207
- if path.isfile(config_file):
208
- __load_config(config_file)
209
- __cli_args.config = config_file
210
- elif config_required:
211
- error("Config file is required, but not found: %s", config_file)
212
- # 如果需要配置文件但没有指定,则自动生成
213
- if generate_config(config_file):
214
- sys.stdout.write("Default configure file %s is generated.\n" % config_file)
215
- sys.exit(1)
216
- else:
217
- sys.exit("fail to load config from file: %s\n" % config_file)
218
-
219
-
220
- def __load_config(config_path):
221
- """
222
- 加载配置
223
- """
224
- global __config
225
- try:
226
- with open(config_path, "r") as configfile:
227
- __config = loadjson(configfile)
228
- __config["config_modified_time"] = stat(config_path).st_mtime
229
- if "log" in __config:
230
- if "level" in __config["log"] and __config["log"]["level"] is not None:
231
- __config["log.level"] = log_level(__config["log"]["level"])
232
- if "file" in __config["log"]:
233
- __config["log.file"] = __config["log"]["file"]
234
- if "format" in __config["log"]:
235
- __config["log.format"] = __config["log"]["format"]
236
- if "datefmt" in __config["log"]:
237
- __config["log.datefmt"] = __config["log"]["datefmt"]
238
- elif "log.level" in __config:
239
- __config["log.level"] = log_level(__config["log.level"])
240
- except Exception as e:
241
- critical("Failed to load config file `%s`: %s", config_path, e)
242
- raise
243
- # 重新抛出异常
244
-
245
-
246
- def get_config(key, default=None):
247
- """
248
- 读取配置
249
- 1. 命令行参数
250
- 2. 配置文件
251
- 3. 环境变量
252
- """
253
- if hasattr(__cli_args, key) and getattr(__cli_args, key) is not None:
254
- return getattr(__cli_args, key)
255
- if key in __config:
256
- return __config.get(key)
257
- # 检查环境变量
258
- env_name = "DDNS_" + key.replace(".", "_") # type:str
259
- variations = [env_name, env_name.upper(), env_name.lower()]
260
- value = next((environ.get(v) for v in variations if v in environ), None)
261
-
262
- # 如果找到环境变量值且参数支持数组,尝试解析为数组
263
- if value is not None and key in ARRAY_PARAMS:
264
- return parse_array_string(value, key in SIMPLE_ARRAY_PARAMS)
265
-
266
- return value if value is not None else default
267
-
268
-
269
- class ExtendAction(Action):
270
- """
271
- 兼容 Python <3.8 的 extend action
272
- """
273
-
274
- def __call__(self, parser, namespace, values, option_string=None):
275
- items = getattr(namespace, self.dest, None)
276
- if items is None:
277
- items = []
278
- # values 可能是单个值或列表
279
- if isinstance(values, list):
280
- items.extend(values)
281
- else:
282
- items.append(values)
283
- setattr(namespace, self.dest, items)
284
-
285
-
286
- def generate_config(config_path):
287
- """
288
- 生成配置文件
289
- """
290
- configure = {
291
- "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
292
- "id": "YOUR ID or EMAIL for DNS Provider",
293
- "token": "YOUR TOKEN or KEY for DNS Provider",
294
- "dns": "debug", # DNS Provider, default is print
295
- "ipv4": ["newfuture.cc", "ddns.newfuture.cc"],
296
- "ipv6": ["newfuture.cc", "ipv6.ddns.newfuture.cc"],
297
- "index4": "default",
298
- "index6": "default",
299
- "ttl": None,
300
- "line": None,
301
- "proxy": None,
302
- "ssl": "auto",
303
- "log": {"level": "INFO"},
304
- }
305
- try:
306
- with open(config_path, "w") as f:
307
- dumpjson(configure, f, indent=2, sort_keys=True)
308
- return True
309
- except IOError:
310
- critical("Cannot open config file to write: `%s`!", config_path)
311
- return False
312
- except Exception as e:
313
- critical("Failed to write config file `%s`: %s", config_path, e)
314
- return False
@@ -1,26 +0,0 @@
1
- ddns/__builtins__.pyi,sha256=QTTtckbWAAZasu-uzeeyK4MLj9S9dxLtRlhty6U01jQ,109
2
- ddns/__init__.py,sha256=i5Ys0GWwE_VEs9egtGsApbc3O_0ne0MRgaDwumTnCas,510
3
- ddns/__main__.py,sha256=I3rjSjbB3ogSayiptGoITQx_9r0DGdxcDsbiGXEID-E,7302
4
- ddns/provider/__init__.py,sha256=P0foc9m2RiiLw6-2JYzNXPShBCGY-G2TIefgdTg-s44,2053
5
- ddns/provider/_base.py,sha256=ohvDJnwazDMAwciqlV430Ic54cTCrI_5l7IAgKaapWE,24600
6
- ddns/provider/alidns.py,sha256=tNKG8CmRZaHC2n3bK0cD3MaiANysT1DsO7H7IQpriic,5514
7
- ddns/provider/callback.py,sha256=XaAu4b4WPcuegPJJBKdQWKY87LPB6BUSRUymPtDPeTc,3006
8
- ddns/provider/cloudflare.py,sha256=Qon3Pg24Q8mE8qouKwwvaPUAP0JNFJ5N7AakpZAv8JU,4514
9
- ddns/provider/debug.py,sha256=3TZYcXHcIzTwUEj5_rvZTT0QqS6jFwTuBS7cMujG2tM,587
10
- ddns/provider/dnscom.py,sha256=nQe8Wi4KTib2Ildf9I2Vz9ZhCd3jkseq9_uZBl-C7P0,3672
11
- ddns/provider/dnspod.py,sha256=MSeB0ZpPnTD2cOjMsF35j2I9Ur4FLZzcKMio74UkX7E,4553
12
- ddns/provider/dnspod_com.py,sha256=G291IowdjAnPGGbsL_9CXfMYyFWxz1AYun5TEY0GvbM,393
13
- ddns/provider/he.py,sha256=gnYZMnsBIvI6ASz1U_tFqnpcUgmobvoOqGOpkWZ9Zew,1835
14
- ddns/provider/huaweidns.py,sha256=hZVYUMPaZUYxSuG2d5QYvnRsG_xrrwfYeNxuI0LqxQM,5597
15
- ddns/provider/tencentcloud.py,sha256=10pe-LwhFSTDMepWIKbcea66384bS2NguZVsl19y5k0,7160
16
- ddns/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- ddns/util/cache.py,sha256=9_QVJzfKxGCysiyE-N46MEKdvXMnco0ZO47vWWOSTPk,4840
18
- ddns/util/config.py,sha256=S0kNBMe1Ot68lLlv05aP01dFOrM07uh9Zpe5JrKZo3k,10646
19
- ddns/util/http.py,sha256=v43Fe7RF6sQ-KTudDQXvjtnvpNoM0UaK1zSa0z5rZGo,10101
20
- ddns/util/ip.py,sha256=-t20yx-McDFpQIrArrzSyetU9lm7irmBtjnxrIfki1w,3909
21
- ddns-4.1.0b1.dist-info/licenses/LICENSE,sha256=MI-ECjp-Vl7WZLiSPY6r5VwrOReNiICVB1QCXiUGt_s,1111
22
- ddns-4.1.0b1.dist-info/METADATA,sha256=8BWmyNOJ5HRvxeizMQT6VXjM90eJFZnhz-qjuchleUk,19211
23
- ddns-4.1.0b1.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
24
- ddns-4.1.0b1.dist-info/entry_points.txt,sha256=2-VbA-WZcjebkZrGKvUCuBBRYF4xQNMoLIoGaS234WU,44
25
- ddns-4.1.0b1.dist-info/top_level.txt,sha256=Se0wn3T8Bc4pj55dGwVrCe8BFwmFCBwQVHF1bTyV0o0,5
26
- ddns-4.1.0b1.dist-info/RECORD,,
File without changes