2 """Loading of configuration files and parameters.
4 @type version: L{twisted.python.versions.Version}
5 @var version: the version of this program
6 @type DEFAULT_CONFIG_FILES: C{list} of C{string}
7 @var DEFAULT_CONFIG_FILES: the default config files to load (in order)
8 @var DEFAULTS: the default config parameter values for the main program
9 @var DHT_DEFAULTS: the default config parameter values for the default DHT
14 from ConfigParser import SafeConfigParser
16 from twisted.python import log, versions
18 class ConfigError(Exception):
19 """Errors that occur in the loading of configuration variables."""
20 def __init__(self, message):
21 self.message = message
23 return repr(self.message)
25 version = versions.Version('apt-p2p', 0, 0, 0)
27 # Set the home parameter
28 home = os.path.expandvars('${HOME}')
29 if home == '${HOME}' or not os.path.isdir(home):
30 home = os.path.expanduser('~')
31 if not os.path.isdir(home):
32 home = os.path.abspath(os.path.dirname(sys.argv[0]))
34 DEFAULT_CONFIG_FILES=['/etc/apt-p2p/apt-p2p.conf',
35 home + '/.apt-p2p/apt-p2p.conf']
39 # Port to listen on for all requests (TCP and UDP)
42 # Directory to store the downloaded files in
43 'CACHE_DIR': home + '/.apt-p2p/cache',
45 # Other directories containing packages to share with others
46 # WARNING: all files in these directories will be hashed and available
47 # for everybody to download
50 # User name to try and run as
53 # Whether it's OK to use an IP addres from a known local/private range
56 # Unload the packages cache after an interval of inactivity this long.
57 # The packages cache uses a lot of memory, and only takes a few seconds
58 # to reload when a new request arrives.
59 'UNLOAD_PACKAGES_CACHE': '5m',
61 # Refresh the DHT keys after this much time has passed.
62 # This should be a time slightly less than the DHT's KEY_EXPIRE value.
65 # Which DHT implementation to use.
66 # It must be possile to do "from <DHT>.DHT import DHT" to get a class that
67 # implements the IDHT interface.
68 'DHT': 'apt_p2p_Khashmir',
70 # Whether to only run the DHT (for providing only a bootstrap node)
75 # bootstrap nodes to contact to join the DHT
76 'BOOTSTRAP': """www.camrdale.org:9977""",
78 # whether this node is a bootstrap node
79 'BOOTSTRAP_NODE': "no",
81 # Kademlia "K" constant, this should be an even number
84 # SHA1 is 160 bits long
87 # checkpoint every this many seconds
88 'CHECKPOINT_INTERVAL': '5m', # five minutes
91 # concurrent xmlrpc calls per find node/value request!
92 'CONCURRENT_REQS': '4',
94 # how many hosts to post to
95 'STORE_REDUNDANCY': '3',
97 # How many values to attempt to retrieve from the DHT.
98 # Setting this to 0 will try and get all values (which could take a while if
99 # a lot of nodes have values). Setting it negative will try to get that
100 # number of results from only the closest STORE_REDUNDANCY nodes to the hash.
101 # The default is a large negative number so all values from the closest
102 # STORE_REDUNDANCY nodes will be retrieved.
103 'RETRIEVE_VALUES': '-10000',
105 ### ROUTING TABLE STUFF
106 # how many times in a row a node can fail to respond before it's booted from the routing table
109 # never ping a node more often than this
110 'MIN_PING_INTERVAL': '15m', # fifteen minutes
112 # refresh buckets that haven't been touched in this long
113 'BUCKET_STALENESS': '1h', # one hour
115 # expire entries older than this
116 'KEY_EXPIRE': '1h', # 60 minutes
118 # whether to spew info about the requests/responses in the protocol
122 class AptP2PConfigParser(SafeConfigParser):
123 """Adds 'gettime' and 'getstringlist' to ConfigParser objects.
125 @ivar time_multipliers: the 'gettime' suffixes and the multipliers needed
126 to convert them to seconds
136 def gettime(self, section, option):
137 """Read the config parameter as a time value."""
139 value = self.get(section, option)
141 raise ConfigError("Configuration parse error: [%s] %s" % (section, option))
142 suffix = value[-1].lower()
143 if suffix in self.time_multipliers.keys():
144 mult = self.time_multipliers[suffix]
146 return int(value)*mult
148 def getstring(self, section, option):
149 """Read the config parameter as a string."""
150 return self.get(section,option)
152 def getstringlist(self, section, option):
153 """Read the multi-line config parameter as a list of strings."""
154 return self.get(section,option).split()
156 def optionxform(self, option):
157 """Use all uppercase in the config parameters names."""
158 return option.upper()
160 # Initialize the default config parameters
161 config = AptP2PConfigParser(DEFAULTS)
162 config.add_section(config.get('DEFAULT', 'DHT'))
163 for k in DHT_DEFAULTS:
164 config.set(config.get('DEFAULT', 'DHT'), k, DHT_DEFAULTS[k])