ConfigDir.py 11 KB

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