Make the upload limit a config option.
[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     # The rate to limit sending data to peers to, in KBytes/sec.
43     # Set this to 0 to not limit the upload bandwidth.
44     'UPLOAD_LIMIT': '0',
45
46     # Directory to store the downloaded files in
47     'CACHE_DIR': home + '/.apt-p2p/cache',
48     
49     # Other directories containing packages to share with others
50     # WARNING: all files in these directories will be hashed and available
51     #          for everybody to download
52     'OTHER_DIRS': """""",
53     
54     # User name to try and run as
55     'USERNAME': '',
56     
57     # Whether it's OK to use an IP address from a known local/private range
58     'LOCAL_OK': 'no',
59
60     # Unload the packages cache after an interval of inactivity this long.
61     # The packages cache uses a lot of memory, and only takes a few seconds
62     # to reload when a new request arrives.
63     'UNLOAD_PACKAGES_CACHE': '5m',
64
65     # Refresh the DHT keys after this much time has passed.
66     # This should be a time slightly less than the DHT's KEY_EXPIRE value.
67     'KEY_REFRESH': '57m',
68
69     # Which DHT implementation to use.
70     # It must be possible to do "from <DHT>.DHT import DHT" to get a class that
71     # implements the IDHT interface.
72     'DHT': 'apt_p2p_Khashmir',
73
74     # Whether to only run the DHT (for providing only a bootstrap node)
75     'DHT-ONLY': 'no',
76 }
77
78 DHT_DEFAULTS = {
79     # bootstrap nodes to contact to join the DHT
80     'BOOTSTRAP': """www.camrdale.org:9977""",
81     
82     # whether this node is a bootstrap node
83     'BOOTSTRAP_NODE': "no",
84     
85     # Kademlia "K" constant, this should be an even number
86     'K': '8',
87     
88     # SHA1 is 160 bits long
89     'HASH_LENGTH': '160',
90     
91     # checkpoint every this many seconds
92     'CHECKPOINT_INTERVAL': '5m', # five minutes
93     
94     ### SEARCHING/STORING
95     # concurrent xmlrpc calls per find node/value request!
96     'CONCURRENT_REQS': '4',
97     
98     # how many hosts to post to
99     'STORE_REDUNDANCY': '3',
100     
101     # How many values to attempt to retrieve from the DHT.
102     # Setting this to 0 will try and get all values (which could take a while if
103     # a lot of nodes have values). Setting it negative will try to get that
104     # number of results from only the closest STORE_REDUNDANCY nodes to the hash.
105     # The default is a large negative number so all values from the closest
106     # STORE_REDUNDANCY nodes will be retrieved.
107     'RETRIEVE_VALUES': '-10000',
108
109     ###  ROUTING TABLE STUFF
110     # how many times in a row a node can fail to respond before it's booted from the routing table
111     'MAX_FAILURES': '3',
112     
113     # never ping a node more often than this
114     'MIN_PING_INTERVAL': '15m', # fifteen minutes
115     
116     # refresh buckets that haven't been touched in this long
117     'BUCKET_STALENESS': '1h', # one hour
118     
119     # expire entries older than this
120     'KEY_EXPIRE': '1h', # 60 minutes
121     
122     # whether to spew info about the requests/responses in the protocol
123     'SPEW': 'yes',
124 }
125
126 class AptP2PConfigParser(SafeConfigParser):
127     """Adds 'gettime' and 'getstringlist' to ConfigParser objects.
128     
129     @ivar time_multipliers: the 'gettime' suffixes and the multipliers needed
130         to convert them to seconds
131     """
132     
133     time_multipliers={
134         's': 1,    #seconds
135         'm': 60,   #minutes
136         'h': 3600, #hours
137         'd': 86400,#days
138         }
139
140     def gettime(self, section, option):
141         """Read the config parameter as a time value."""
142         mult = 1
143         value = self.get(section, option)
144         if len(value) == 0:
145             raise ConfigError("Configuration parse error: [%s] %s" % (section, option))
146         suffix = value[-1].lower()
147         if suffix in self.time_multipliers.keys():
148             mult = self.time_multipliers[suffix]
149             value = value[:-1]
150         return int(value)*mult
151     
152     def getstring(self, section, option):
153         """Read the config parameter as a string."""
154         return self.get(section,option)
155     
156     def getstringlist(self, section, option):
157         """Read the multi-line config parameter as a list of strings."""
158         return self.get(section,option).split()
159
160     def optionxform(self, option):
161         """Use all uppercase in the config parameters names."""
162         return option.upper()
163
164 # Initialize the default config parameters
165 config = AptP2PConfigParser(DEFAULTS)
166 config.add_section(config.get('DEFAULT', 'DHT'))
167 for k in DHT_DEFAULTS:
168     config.set(config.get('DEFAULT', 'DHT'), k, DHT_DEFAULTS[k])