]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - www/pages/torrent/client/ConfigDir.py
Change Color of Menuitem CeBIT.
[people/shoehn/ipfire.org.git] / www / pages / torrent / client / ConfigDir.py
1 #written by John Hoffman
2
3 from inifile import ini_write, ini_read
4 from bencode import bencode, bdecode
5 from types import IntType, LongType, StringType, FloatType
6 from CreateIcons import GetIcons, CreateIcon
7 from parseargs import defaultargs
8 from __init__ import product_name, version_short
9 import sys,os
10 from time import time, strftime
11
12 try:
13 True
14 except:
15 True = 1
16 False = 0
17
18 try:
19 realpath = os.path.realpath
20 except:
21 realpath = lambda x:x
22 OLDICONPATH = os.path.abspath(os.path.dirname(realpath(sys.argv[0])))
23
24 DIRNAME = '.'+product_name
25
26 hexchars = '0123456789abcdef'
27 hexmap = []
28 revmap = {}
29 for i in xrange(256):
30 x = hexchars[(i&0xF0)/16]+hexchars[i&0x0F]
31 hexmap.append(x)
32 revmap[x] = chr(i)
33
34 def tohex(s):
35 r = []
36 for c in s:
37 r.append(hexmap[ord(c)])
38 return ''.join(r)
39
40 def unhex(s):
41 r = [ revmap[s[x:x+2]] for x in xrange(0, len(s), 2) ]
42 return ''.join(r)
43
44 def copyfile(oldpath, newpath): # simple file copy, all in RAM
45 try:
46 f = open(oldpath,'rb')
47 r = f.read()
48 success = True
49 except:
50 success = False
51 try:
52 f.close()
53 except:
54 pass
55 if not success:
56 return False
57 try:
58 f = open(newpath,'wb')
59 f.write(r)
60 except:
61 success = False
62 try:
63 f.close()
64 except:
65 pass
66 return success
67
68
69 class ConfigDir:
70
71 ###### INITIALIZATION TASKS ######
72
73 def __init__(self, config_type = None):
74 self.config_type = config_type
75 if config_type:
76 config_ext = '.'+config_type
77 else:
78 config_ext = ''
79
80 def check_sysvars(x):
81 y = os.path.expandvars(x)
82 if y != x and os.path.isdir(y):
83 return y
84 return None
85
86 for d in ['${APPDATA}', '${HOME}', '${HOMEPATH}', '${USERPROFILE}']:
87 dir_root = check_sysvars(d)
88 if dir_root:
89 break
90 else:
91 dir_root = os.path.expanduser('~')
92 if not os.path.isdir(dir_root):
93 dir_root = os.path.abspath(os.path.dirname(sys.argv[0]))
94
95 dir_root = os.path.join(dir_root,DIRNAME)
96 self.dir_root = dir_root
97
98 if not os.path.isdir(self.dir_root):
99 os.mkdir(self.dir_root,0700) # exception if failed
100
101 self.dir_icons = os.path.join(dir_root,'icons')
102 if not os.path.isdir(self.dir_icons):
103 os.mkdir(self.dir_icons)
104 for icon in GetIcons():
105 i = os.path.join(self.dir_icons,icon)
106 if not os.path.exists(i):
107 if not copyfile(os.path.join(OLDICONPATH,icon),i):
108 CreateIcon(icon,self.dir_icons)
109
110 self.dir_torrentcache = os.path.join(dir_root,'torrentcache')
111 if not os.path.isdir(self.dir_torrentcache):
112 os.mkdir(self.dir_torrentcache)
113
114 self.dir_datacache = os.path.join(dir_root,'datacache')
115 if not os.path.isdir(self.dir_datacache):
116 os.mkdir(self.dir_datacache)
117
118 self.dir_piececache = os.path.join(dir_root,'piececache')
119 if not os.path.isdir(self.dir_piececache):
120 os.mkdir(self.dir_piececache)
121
122 self.configfile = os.path.join(dir_root,'config'+config_ext+'.ini')
123 self.statefile = os.path.join(dir_root,'state'+config_ext)
124
125 self.TorrentDataBuffer = {}
126
127
128 ###### CONFIG HANDLING ######
129
130 def setDefaults(self, defaults, ignore=[]):
131 self.config = defaultargs(defaults)
132 for k in ignore:
133 if self.config.has_key(k):
134 del self.config[k]
135
136 def checkConfig(self):
137 return os.path.exists(self.configfile)
138
139 def loadConfig(self):
140 try:
141 r = ini_read(self.configfile)['']
142 except:
143 return self.config
144 l = self.config.keys()
145 for k,v in r.items():
146 if self.config.has_key(k):
147 t = type(self.config[k])
148 try:
149 if t == StringType:
150 self.config[k] = v
151 elif t == IntType or t == LongType:
152 self.config[k] = long(v)
153 elif t == FloatType:
154 self.config[k] = float(v)
155 l.remove(k)
156 except:
157 pass
158 if l: # new default values since last save
159 self.saveConfig()
160 return self.config
161
162 def saveConfig(self, new_config = None):
163 if new_config:
164 for k,v in new_config.items():
165 if self.config.has_key(k):
166 self.config[k] = v
167 try:
168 ini_write( self.configfile, self.config,
169 'Generated by '+product_name+'/'+version_short+'\n'
170 + strftime('%x %X') )
171 return True
172 except:
173 return False
174
175 def getConfig(self):
176 return self.config
177
178
179 ###### STATE HANDLING ######
180
181 def getState(self):
182 try:
183 f = open(self.statefile,'rb')
184 r = f.read()
185 except:
186 r = None
187 try:
188 f.close()
189 except:
190 pass
191 try:
192 r = bdecode(r)
193 except:
194 r = None
195 return r
196
197 def saveState(self, state):
198 try:
199 f = open(self.statefile,'wb')
200 f.write(bencode(state))
201 success = True
202 except:
203 success = False
204 try:
205 f.close()
206 except:
207 pass
208 return success
209
210
211 ###### TORRENT HANDLING ######
212
213 def getTorrents(self):
214 d = {}
215 for f in os.listdir(self.dir_torrentcache):
216 f = os.path.basename(f)
217 try:
218 f, garbage = f.split('.')
219 except:
220 pass
221 d[unhex(f)] = 1
222 return d.keys()
223
224 def getTorrentVariations(self, t):
225 t = tohex(t)
226 d = []
227 for f in os.listdir(self.dir_torrentcache):
228 f = os.path.basename(f)
229 if f[:len(t)] == t:
230 try:
231 garbage, ver = f.split('.')
232 except:
233 ver = '0'
234 d.append(int(ver))
235 d.sort()
236 return d
237
238 def getTorrent(self, t, v = -1):
239 t = tohex(t)
240 if v == -1:
241 v = max(self.getTorrentVariations(t)) # potential exception
242 if v:
243 t += '.'+str(v)
244 try:
245 f = open(os.path.join(self.dir_torrentcache,t),'rb')
246 r = bdecode(f.read())
247 except:
248 r = None
249 try:
250 f.close()
251 except:
252 pass
253 return r
254
255 def writeTorrent(self, data, t, v = -1):
256 t = tohex(t)
257 if v == -1:
258 try:
259 v = max(self.getTorrentVariations(t))+1
260 except:
261 v = 0
262 if v:
263 t += '.'+str(v)
264 try:
265 f = open(os.path.join(self.dir_torrentcache,t),'wb')
266 f.write(bencode(data))
267 except:
268 v = None
269 try:
270 f.close()
271 except:
272 pass
273 return v
274
275
276 ###### TORRENT DATA HANDLING ######
277
278 def getTorrentData(self, t):
279 if self.TorrentDataBuffer.has_key(t):
280 return self.TorrentDataBuffer[t]
281 t = os.path.join(self.dir_datacache,tohex(t))
282 if not os.path.exists(t):
283 return None
284 try:
285 f = open(t,'rb')
286 r = bdecode(f.read())
287 except:
288 r = None
289 try:
290 f.close()
291 except:
292 pass
293 self.TorrentDataBuffer[t] = r
294 return r
295
296 def writeTorrentData(self, t, data):
297 self.TorrentDataBuffer[t] = data
298 try:
299 f = open(os.path.join(self.dir_datacache,tohex(t)),'wb')
300 f.write(bencode(data))
301 success = True
302 except:
303 success = False
304 try:
305 f.close()
306 except:
307 pass
308 if not success:
309 self.deleteTorrentData(t)
310 return success
311
312 def deleteTorrentData(self, t):
313 try:
314 os.remove(os.path.join(self.dir_datacache,tohex(t)))
315 except:
316 pass
317
318 def getPieceDir(self, t):
319 return os.path.join(self.dir_piececache,tohex(t))
320
321
322 ###### EXPIRATION HANDLING ######
323
324 def deleteOldCacheData(self, days, still_active = [], delete_torrents = False):
325 if not days:
326 return
327 exptime = time() - (days*24*3600)
328 names = {}
329 times = {}
330
331 for f in os.listdir(self.dir_torrentcache):
332 p = os.path.join(self.dir_torrentcache,f)
333 f = os.path.basename(f)
334 try:
335 f, garbage = f.split('.')
336 except:
337 pass
338 try:
339 f = unhex(f)
340 assert len(f) == 20
341 except:
342 continue
343 if delete_torrents:
344 names.setdefault(f,[]).append(p)
345 try:
346 t = os.path.getmtime(p)
347 except:
348 t = time()
349 times.setdefault(f,[]).append(t)
350
351 for f in os.listdir(self.dir_datacache):
352 p = os.path.join(self.dir_datacache,f)
353 try:
354 f = unhex(os.path.basename(f))
355 assert len(f) == 20
356 except:
357 continue
358 names.setdefault(f,[]).append(p)
359 try:
360 t = os.path.getmtime(p)
361 except:
362 t = time()
363 times.setdefault(f,[]).append(t)
364
365 for f in os.listdir(self.dir_piececache):
366 p = os.path.join(self.dir_piececache,f)
367 try:
368 f = unhex(os.path.basename(f))
369 assert len(f) == 20
370 except:
371 continue
372 for f2 in os.listdir(p):
373 p2 = os.path.join(p,f2)
374 names.setdefault(f,[]).append(p2)
375 try:
376 t = os.path.getmtime(p2)
377 except:
378 t = time()
379 times.setdefault(f,[]).append(t)
380 names.setdefault(f,[]).append(p)
381
382 for k,v in times.items():
383 if max(v) < exptime and not k in still_active:
384 for f in names[k]:
385 try:
386 os.remove(f)
387 except:
388 try:
389 os.removedirs(f)
390 except:
391 pass
392
393
394 def deleteOldTorrents(self, days, still_active = []):
395 self.deleteOldCacheData(days, still_active, True)
396
397
398 ###### OTHER ######
399
400 def getIconDir(self):
401 return self.dir_icons