Rename all apt-dht files to apt-p2p.
[quix0rs-apt-p2p.git] / apt_p2p / apt_p2p_conf.py
1
2 """Loading of configuration files and parameters.
3
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
10
11 """
12
13 import os, sys
14 from ConfigParser import SafeConfigParser
15
16 from twisted.python import log, versions
17
18 class ConfigError(Exception):
19     """Errors that occur in the loading of configuration variables."""
20     def __init__(self, message):
21         self.message = message
22     def __str__(self):
23         return repr(self.message)
24
25 version = versions.Version('apt-p2p', 0, 0, 0)
26
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]))
33
34 DEFAULT_CONFIG_FILES=['/etc/apt-p2p/apt-p2p.conf',
35                       home + '/.apt-p2p/apt-p2p.conf']
36
37 DEFAULTS = {
38
39     # Port to listen on for all requests (TCP and UDP)
40     'PORT': '9977',
41     
42     # Directory to store the downloaded files in
43     'CACHE_DIR': home + '/.apt-p2p/cache',
44     
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
48     'OTHER_DIRS': """""",
49     
50     # User name to try and run as
51     'USERNAME': '',
52     
53     # Whether it's OK to use an IP addres from a known local/private range
54     'LOCAL_OK': 'no',
55
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',
60
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.
63     'KEY_REFRESH': '57m',
64
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',
69
70     # Whether to only run the DHT (for providing only a bootstrap node)
71     'DHT-ONLY': 'no',
72 }
73
74 DHT_DEFAULTS = {
75     # bootstrap nodes to contact to join the DHT
76     'BOOTSTRAP': """www.camrdale.org:9977
77         steveholt.hopto.org:9976""",
78     
79     # whether this node is a bootstrap node
80     'BOOTSTRAP_NODE': "no",
81     
82     # Kademlia "K" constant, this should be an even number
83     'K': '8',
84     
85     # SHA1 is 160 bits long
86     'HASH_LENGTH': '160',
87     
88     # checkpoint every this many seconds
89     'CHECKPOINT_INTERVAL': '5m', # five minutes
90     
91     ### SEARCHING/STORING
92     # concurrent xmlrpc calls per find node/value request!
93     'CONCURRENT_REQS': '4',
94     
95     # how many hosts to post to
96     'STORE_REDUNDANCY': '3',
97     
98     # How many values to attempt to retrieve from the DHT.
99     # Setting this to 0 will try and get all values (which could take a while if
100     # a lot of nodes have values). Setting it negative will try to get that
101     # number of results from only the closest STORE_REDUNDANCY nodes to the hash.
102     # The default is a large negative number so all values from the closest
103     # STORE_REDUNDANCY nodes will be retrieved.
104     'RETRIEVE_VALUES': '-10000',
105
106     ###  ROUTING TABLE STUFF
107     # how many times in a row a node can fail to respond before it's booted from the routing table
108     'MAX_FAILURES': '3',
109     
110     # never ping a node more often than this
111     'MIN_PING_INTERVAL': '15m', # fifteen minutes
112     
113     # refresh buckets that haven't been touched in this long
114     'BUCKET_STALENESS': '1h', # one hour
115     
116     # expire entries older than this
117     'KEY_EXPIRE': '1h', # 60 minutes
118     
119     # whether to spew info about the requests/responses in the protocol
120     'SPEW': 'yes',
121 }
122
123 class AptP2PConfigParser(SafeConfigParser):
124     """Adds 'gettime' and 'getstringlist' to ConfigParser objects.
125     
126     @ivar time_multipliers: the 'gettime' suffixes and the multipliers needed
127         to convert them to seconds
128     """
129     
130     time_multipliers={
131         's': 1,    #seconds
132         'm': 60,   #minutes
133         'h': 3600, #hours
134         'd': 86400,#days
135         }
136
137     def gettime(self, section, option):
138         """Read the config parameter as a time value."""
139         mult = 1
140         value = self.get(section, option)
141         if len(value) == 0:
142             raise ConfigError("Configuration parse error: [%s] %s" % (section, option))
143         suffix = value[-1].lower()
144         if suffix in self.time_multipliers.keys():
145             mult = self.time_multipliers[suffix]
146             value = value[:-1]
147         return int(value)*mult
148     
149     def getstring(self, section, option):
150         """Read the config parameter as a string."""
151         return self.get(section,option)
152     
153     def getstringlist(self, section, option):
154         """Read the multi-line config parameter as a list of strings."""
155         return self.get(section,option).split()
156
157     def optionxform(self, option):
158         """Use all uppercase in the config parameters names."""
159         return option.upper()
160
161 # Initialize the default config parameters
162 config = AptP2PConfigParser(DEFAULTS)
163 config.add_section(config.get('DEFAULT', 'DHT'))
164 for k in DHT_DEFAULTS:
165     config.set(config.get('DEFAULT', 'DHT'), k, DHT_DEFAULTS[k])