Skip to content

Commit 618f08e

Browse files
authored
feat(config): 优化配置文件加载逻辑,支持用户目录和系统目录 (NewFuture#468)
* feat(config): Optimize configuration file loading logic 当前目录 config.json 用户目录 ~/.ddns/config.json 系统目录 /etc/ddns/config.json
1 parent f5602d8 commit 618f08e

3 files changed

Lines changed: 99 additions & 71 deletions

File tree

_config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
markdown: kramdown
2+
3+
favicon: /doc/img/ddns.svg
4+
site_favicon: /doc/img/ddns.svg
5+
26
kramdown:
37
parse_block_html: true
48

run.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def get_ip(ip_type, index="default"):
4747
debug("get_ip(%s, %s)", ip_type, index)
4848
if index is False: # disabled
4949
return False
50-
elif isinstance(index, list): # 如果获取到的规则是列表,则依次判断列表中每一个规则,直到找到一个可以正确获取到的IP
50+
elif isinstance(index, list): # 如果获取到的规则是列表,则依次判断列表中每一个规则,直到获取到IP
5151
for i in index:
5252
value = get_ip(ip_type, i)
5353
if value:
@@ -66,7 +66,7 @@ def get_ip(ip_type, index="default"):
6666
else:
6767
value = getattr(ip, index + "_v" + ip_type)()
6868
except Exception as e:
69-
error(e)
69+
error("Failed to get %s address: %s", ip_type, e)
7070
return value
7171

7272

@@ -81,7 +81,7 @@ def change_dns_record(dns, proxy_list, **kw):
8181
try:
8282
return dns.update_record(domain, kw['ip'], record_type=record_type)
8383
except Exception as e:
84-
error(e)
84+
error("Failed to update %s record for %s: %s", record_type, domain, e)
8585
return False
8686

8787

@@ -136,11 +136,11 @@ def main():
136136

137137
info("DDNS[ %s ] run: %s %s", __version__, os_name, sys.platform)
138138
if get_config("config"):
139-
info("loaded Config from: %s", path.abspath(get_config('config')))
139+
info('loaded Config from: %s', path.abspath(get_config('config')))
140140

141141
proxy = get_config('proxy') or 'DIRECT'
142142
proxy_list = proxy if isinstance(
143-
proxy, list) else proxy.strip('; ').replace(',', ';').split(';')
143+
proxy, list) else proxy.strip(';').replace(',', ';').split(';')
144144

145145
cache_config = get_config('cache', True)
146146
if cache_config is False:
@@ -151,12 +151,12 @@ def main():
151151
cache = Cache(cache_config)
152152

153153
if cache is False:
154-
info("Cache is disabled!")
155-
elif get_config("config_modified_time") is None or get_config("config_modified_time") >= cache.time:
156-
warning("Cache file is out of dated.")
154+
info('Cache is disabled!')
155+
elif not get_config('config_modified_time') or get_config('config_modified_time') >= cache.time:
156+
warning('Cache file is out of dated.')
157157
cache.clear()
158158
else:
159-
debug("Cache is empty.")
159+
debug('Cache is empty.')
160160
update_ip('4', cache, dns, proxy_list)
161161
update_ip('6', cache, dns, proxy_list)
162162

util/config.py

Lines changed: 86 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
# -*- coding:utf-8 -*-
33
from argparse import Action, ArgumentParser, Namespace, RawTextHelpFormatter
44
from json import load as loadjson, dump as dumpjson
5-
from os import stat, environ
5+
from os import stat, environ, path
66
from logging import error, getLevelName
77

8-
from time import time
9-
108
import sys
119

1210

@@ -46,89 +44,77 @@ def init_config(description, doc, version):
4644
epilog=doc, formatter_class=RawTextHelpFormatter)
4745
parser.add_argument('-v', '--version',
4846
action='version', version=version)
49-
parser.add_argument('-c', '--config', help="run with config file [配置文件路径]")
47+
parser.add_argument('-c', '--config', help='run with config file [配置文件路径]')
5048

5149
# 参数定义
52-
parser.add_argument('--dns', help="DNS Provider [DNS服务提供商]", choices=[
50+
parser.add_argument('--dns', help='DNS Provider [DNS服务提供商]', choices=[
5351
'alidns', 'cloudflare', 'dnscom', 'dnspod', 'dnspod_com', 'he', 'huaweidns', 'callback'])
54-
parser.add_argument('--id', help="api ID [授权账户]")
55-
parser.add_argument('--token', help="api token or Secret key [授权访问凭证或密钥]")
56-
parser.add_argument('--index4', nargs="*", action=ExtendAction,
57-
help="list to get ipv4 [IPV4 获取方式]")
58-
parser.add_argument('--index6', nargs="*", action=ExtendAction,
59-
help="list to get ipv6 [IPV6获取方式]")
60-
parser.add_argument('--ipv4', nargs="*", action=ExtendAction,
61-
help="ipv4 domain list [IPV4域名列表]")
62-
parser.add_argument('--ipv6', nargs="*", action=ExtendAction,
63-
help="ipv6 domain list [IPV6域名列表]")
64-
parser.add_argument('--ttl', type=int, help="ttl for DNS [DNS 解析 TTL 时间]")
65-
parser.add_argument('--proxy', nargs="*", action=ExtendAction,
66-
help="https proxy [设置http 代理,多代理逐个尝试直到成功]")
52+
parser.add_argument('--id', help='api ID [授权账户]')
53+
parser.add_argument('--token', help='api token or Secret key [授权访问凭证或密钥]')
54+
parser.add_argument('--index4', nargs='*', action=ExtendAction,
55+
help='list to get ipv4 [IPV4 获取方式]')
56+
parser.add_argument('--index6', nargs='*', action=ExtendAction,
57+
help='list to get ipv6 [IPV6获取方式]')
58+
parser.add_argument('--ipv4', nargs='*', action=ExtendAction,
59+
help='ipv4 domain list [IPV4域名列表]')
60+
parser.add_argument('--ipv6', nargs='*', action=ExtendAction,
61+
help='ipv6 domain list [IPV6域名列表]')
62+
parser.add_argument('--ttl', type=int, help='ttl for DNS [DNS 解析 TTL 时间]')
63+
parser.add_argument('--proxy', nargs='*', action=ExtendAction,
64+
help='https proxy [设置http 代理,多代理逐个尝试直到成功]')
6765
parser.add_argument('--cache', type=str2bool, nargs='?',
68-
const=True, help="cache flag [启用缓存,可配配置路径或开关]")
69-
parser.add_argument('--log.file', metavar="LOG_FILE",
70-
help="log file [日志文件,默认标准输出]")
66+
const=True, help='cache flag [启用缓存,可配配置路径或开关]')
67+
parser.add_argument('--log.file', metavar='LOG_FILE',
68+
help='log file [日志文件,默认标准输出]')
7169
parser.add_argument('--log.level', type=log_level,
72-
metavar="|".join(log_levels))
70+
metavar='|'.join(log_levels))
7371

7472
__cli_args = parser.parse_args()
75-
is_configfile_optional = get_config("token") or get_config("id")
73+
is_configfile_required = not get_config("token") and not get_config("id")
7674
config_file = get_config("config")
77-
if not is_configfile_optional or config_file is not None:
78-
__load_config(config_file or "config.json", is_configfile_optional)
79-
__cli_args.config = config_file or "config.json"
75+
if not config_file:
76+
# 未指定配置文件且需要读取文件时,依次查找
77+
cfgs = [
78+
path.abspath('config.json'),
79+
path.expanduser('~/.ddns/config.json'),
80+
'/etc/ddns/config.json'
81+
]
82+
config_file = next((cfg for cfg in cfgs if path.isfile(cfg)), cfgs[0])
83+
84+
if path.isfile(config_file):
85+
__load_config(config_file)
86+
__cli_args.config = config_file
87+
elif is_configfile_required:
88+
error('Config file is required, but not found: %s', config_file)
89+
# 如果需要配置文件但没有指定,则自动生成
90+
if generate_config(config_file):
91+
sys.stdout.write(
92+
'Default configure file %s is generated.\n' % config_file)
93+
sys.exit(1)
94+
else:
95+
sys.exit('fail to load config from file: %s\n' % config_file)
8096

8197

82-
def __load_config(path="config.json", skip_auto_generation=False):
98+
def __load_config(config_path):
8399
"""
84100
加载配置
85101
"""
86102
global __config
87103
try:
88-
with open(path) as configfile:
104+
with open(config_path, 'r') as configfile:
89105
__config = loadjson(configfile)
90-
__config["config_modified_time"] = stat(path).st_mtime
106+
__config["config_modified_time"] = stat(config_path).st_mtime
91107
if 'log' in __config:
92108
if 'level' in __config['log'] and __config['log']['level'] is not None:
93109
__config['log.level'] = log_level(__config['log']['level'])
94110
if 'file' in __config['log']:
95111
__config['log.file'] = __config['log']['file']
96112
elif 'log.level' in __config:
97113
__config['log.level'] = log_level(__config['log.level'])
98-
except IOError:
99-
if skip_auto_generation:
100-
__config["config_modified_time"] = time()
101-
return
102-
error(' Config file `%s` does not exist!' % path)
103-
with open(path, 'w') as configfile:
104-
configure = {
105-
"$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
106-
"id": "YOUR ID or EMAIL for DNS Provider",
107-
"token": "YOUR TOKEN or KEY for DNS Provider",
108-
"dns": "dnspod",
109-
"ipv4": [
110-
"newfuture.cc",
111-
"ddns.newfuture.cc"
112-
],
113-
"ipv6": [
114-
"newfuture.cc",
115-
"ipv6.ddns.newfuture.cc"
116-
],
117-
"index4": "default",
118-
"index6": "default",
119-
"ttl": None,
120-
"proxy": None,
121-
"log": {
122-
"level": "INFO",
123-
"file": None
124-
}
125-
}
126-
dumpjson(configure, configfile, indent=2, sort_keys=True)
127-
sys.stdout.write(
128-
"New template configure file `%s` is generated.\n" % path)
129-
sys.exit(1)
130114
except Exception as e:
131-
sys.exit('fail to load config from file: %s\n%s' % (path, e))
115+
error('Failed to load config file `%s`: %s', config_path, e)
116+
raise
117+
# 重新抛出异常
132118

133119

134120
def get_config(key, default=None):
@@ -167,3 +153,41 @@ def __call__(self, parser, namespace, values, option_string=None):
167153
else:
168154
items.append(values)
169155
setattr(namespace, self.dest, items)
156+
157+
158+
def generate_config(config_path):
159+
"""
160+
生成配置文件
161+
"""
162+
configure = {
163+
'$schema': 'https://ddns.newfuture.cc/schema/v4.0.json',
164+
'id': 'YOUR ID or EMAIL for DNS Provider',
165+
'token': 'YOUR TOKEN or KEY for DNS Provider',
166+
'dns': 'dnspod',
167+
'ipv4': [
168+
'newfuture.cc',
169+
'ddns.newfuture.cc'
170+
],
171+
'ipv6': [
172+
'newfuture.cc',
173+
'ipv6.ddns.newfuture.cc'
174+
],
175+
'index4': 'default',
176+
'index6': 'default',
177+
'ttl': None,
178+
'proxy': None,
179+
'log': {
180+
'level': 'INFO',
181+
'file': None
182+
}
183+
}
184+
try:
185+
with open(config_path, 'w') as f:
186+
dumpjson(configure, f, indent=2, sort_keys=True)
187+
return True
188+
except IOError:
189+
error('Cannot open config file to write: `%s`!', config_path)
190+
return False
191+
except Exception as e:
192+
error('Failed to write config file `%s`: %s', config_path, e)
193+
return False

0 commit comments

Comments
 (0)