Blame | Last modification | View Log | Download
#written by John Hoffman
from inifile import ini_write, ini_read
from bencode import bencode, bdecode
from types import IntType, LongType, StringType, FloatType
from CreateIcons import GetIcons, CreateIcon
from parseargs import defaultargs
from __init__ import product_name, version_short
import sys,os
from time import time, strftime
try:
True
except:
True = 1
False = 0
try:
realpath = os.path.realpath
except:
realpath = lambda x:x
OLDICONPATH = os.path.abspath(os.path.dirname(realpath(sys.argv[0])))
DIRNAME = '.'+product_name
hexchars = '0123456789abcdef'
hexmap = []
revmap = {}
for i in xrange(256):
x = hexchars[(i&0xF0)/16]+hexchars[i&0x0F]
hexmap.append(x)
revmap[x] = chr(i)
def tohex(s):
r = []
for c in s:
r.append(hexmap[ord(c)])
return ''.join(r)
def unhex(s):
r = [ revmap[s[x:x+2]] for x in xrange(0, len(s), 2) ]
return ''.join(r)
def copyfile(oldpath, newpath): # simple file copy, all in RAM
try:
f = open(oldpath,'rb')
r = f.read()
success = True
except:
success = False
try:
f.close()
except:
pass
if not success:
return False
try:
f = open(newpath,'wb')
f.write(r)
except:
success = False
try:
f.close()
except:
pass
return success
class ConfigDir:
###### INITIALIZATION TASKS ######
def __init__(self, config_type = None):
self.config_type = config_type
if config_type:
config_ext = '.'+config_type
else:
config_ext = ''
def check_sysvars(x):
y = os.path.expandvars(x)
if y != x and os.path.isdir(y):
return y
return None
for d in ['${APPDATA}', '${HOME}', '${HOMEPATH}', '${USERPROFILE}']:
dir_root = check_sysvars(d)
if dir_root:
break
else:
dir_root = os.path.expanduser('~')
if not os.path.isdir(dir_root):
dir_root = os.path.abspath(os.path.dirname(sys.argv[0]))
dir_root = os.path.join(dir_root,DIRNAME)
self.dir_root = dir_root
if not os.path.isdir(self.dir_root):
os.mkdir(self.dir_root,0700) # exception if failed
self.dir_icons = os.path.join(dir_root,'icons')
if not os.path.isdir(self.dir_icons):
os.mkdir(self.dir_icons)
for icon in GetIcons():
i = os.path.join(self.dir_icons,icon)
if not os.path.exists(i):
if not copyfile(os.path.join(OLDICONPATH,icon),i):
CreateIcon(icon,self.dir_icons)
self.dir_torrentcache = os.path.join(dir_root,'torrentcache')
if not os.path.isdir(self.dir_torrentcache):
os.mkdir(self.dir_torrentcache)
self.dir_datacache = os.path.join(dir_root,'datacache')
if not os.path.isdir(self.dir_datacache):
os.mkdir(self.dir_datacache)
self.dir_piececache = os.path.join(dir_root,'piececache')
if not os.path.isdir(self.dir_piececache):
os.mkdir(self.dir_piececache)
self.configfile = os.path.join(dir_root,'config'+config_ext+'.ini')
self.statefile = os.path.join(dir_root,'state'+config_ext)
self.TorrentDataBuffer = {}
###### CONFIG HANDLING ######
def setDefaults(self, defaults, ignore=[]):
self.config = defaultargs(defaults)
for k in ignore:
if self.config.has_key(k):
del self.config[k]
def checkConfig(self):
return os.path.exists(self.configfile)
def loadConfig(self):
try:
r = ini_read(self.configfile)['']
except:
return self.config
l = self.config.keys()
for k,v in r.items():
if self.config.has_key(k):
t = type(self.config[k])
try:
if t == StringType:
self.config[k] = v
elif t == IntType or t == LongType:
self.config[k] = long(v)
elif t == FloatType:
self.config[k] = float(v)
l.remove(k)
except:
pass
if l: # new default values since last save
self.saveConfig()
return self.config
def saveConfig(self, new_config = None):
if new_config:
for k,v in new_config.items():
if self.config.has_key(k):
self.config[k] = v
try:
ini_write( self.configfile, self.config,
'Generated by '+product_name+'/'+version_short+'\n'
+ strftime('%x %X') )
return True
except:
return False
def getConfig(self):
return self.config
###### STATE HANDLING ######
def getState(self):
try:
f = open(self.statefile,'rb')
r = f.read()
except:
r = None
try:
f.close()
except:
pass
try:
r = bdecode(r)
except:
r = None
return r
def saveState(self, state):
try:
f = open(self.statefile,'wb')
f.write(bencode(state))
success = True
except:
success = False
try:
f.close()
except:
pass
return success
###### TORRENT HANDLING ######
def getTorrents(self):
d = {}
for f in os.listdir(self.dir_torrentcache):
f = os.path.basename(f)
try:
f, garbage = f.split('.')
except:
pass
d[unhex(f)] = 1
return d.keys()
def getTorrentVariations(self, t):
t = tohex(t)
d = []
for f in os.listdir(self.dir_torrentcache):
f = os.path.basename(f)
if f[:len(t)] == t:
try:
garbage, ver = f.split('.')
except:
ver = '0'
d.append(int(ver))
d.sort()
return d
def getTorrent(self, t, v = -1):
t = tohex(t)
if v == -1:
v = max(self.getTorrentVariations(t)) # potential exception
if v:
t += '.'+str(v)
try:
f = open(os.path.join(self.dir_torrentcache,t),'rb')
r = bdecode(f.read())
except:
r = None
try:
f.close()
except:
pass
return r
def writeTorrent(self, data, t, v = -1):
t = tohex(t)
if v == -1:
try:
v = max(self.getTorrentVariations(t))+1
except:
v = 0
if v:
t += '.'+str(v)
try:
f = open(os.path.join(self.dir_torrentcache,t),'wb')
f.write(bencode(data))
except:
v = None
try:
f.close()
except:
pass
return v
###### TORRENT DATA HANDLING ######
def getTorrentData(self, t):
if self.TorrentDataBuffer.has_key(t):
return self.TorrentDataBuffer[t]
t = os.path.join(self.dir_datacache,tohex(t))
if not os.path.exists(t):
return None
try:
f = open(t,'rb')
r = bdecode(f.read())
except:
r = None
try:
f.close()
except:
pass
self.TorrentDataBuffer[t] = r
return r
def writeTorrentData(self, t, data):
self.TorrentDataBuffer[t] = data
try:
f = open(os.path.join(self.dir_datacache,tohex(t)),'wb')
f.write(bencode(data))
success = True
except:
success = False
try:
f.close()
except:
pass
if not success:
self.deleteTorrentData(t)
return success
def deleteTorrentData(self, t):
try:
os.remove(os.path.join(self.dir_datacache,tohex(t)))
except:
pass
def getPieceDir(self, t):
return os.path.join(self.dir_piececache,tohex(t))
###### EXPIRATION HANDLING ######
def deleteOldCacheData(self, days, still_active = [], delete_torrents = False):
if not days:
return
exptime = time() - (days*24*3600)
names = {}
times = {}
for f in os.listdir(self.dir_torrentcache):
p = os.path.join(self.dir_torrentcache,f)
f = os.path.basename(f)
try:
f, garbage = f.split('.')
except:
pass
try:
f = unhex(f)
assert len(f) == 20
except:
continue
if delete_torrents:
names.setdefault(f,[]).append(p)
try:
t = os.path.getmtime(p)
except:
t = time()
times.setdefault(f,[]).append(t)
for f in os.listdir(self.dir_datacache):
p = os.path.join(self.dir_datacache,f)
try:
f = unhex(os.path.basename(f))
assert len(f) == 20
except:
continue
names.setdefault(f,[]).append(p)
try:
t = os.path.getmtime(p)
except:
t = time()
times.setdefault(f,[]).append(t)
for f in os.listdir(self.dir_piececache):
p = os.path.join(self.dir_piececache,f)
try:
f = unhex(os.path.basename(f))
assert len(f) == 20
except:
continue
for f2 in os.listdir(p):
p2 = os.path.join(p,f2)
names.setdefault(f,[]).append(p2)
try:
t = os.path.getmtime(p2)
except:
t = time()
times.setdefault(f,[]).append(t)
names.setdefault(f,[]).append(p)
for k,v in times.items():
if max(v) < exptime and not k in still_active:
for f in names[k]:
try:
os.remove(f)
except:
try:
os.removedirs(f)
except:
pass
def deleteOldTorrents(self, days, still_active = []):
self.deleteOldCacheData(days, still_active, True)
###### OTHER ######
def getIconDir(self):
return self.dir_icons