Initial commit
This commit is contained in:
commit
a73140ee37
36 files changed
+4081
No files matched your search
@@ -0,0 +1,325 @@
|
||||
from twisted.web import static, resource
|
||||
from twisted.internet import reactor
|
||||
import sys, os, atexit, glob, imp
|
||||
|
||||
from Hatenatools import *#UGO, PPM, TMB and NTFT
|
||||
ServerLog = None#Is set to the log class by server.py
|
||||
|
||||
Silent = False
|
||||
def Log(request, path=None):
|
||||
if not path:
|
||||
path = "\"%s\"" % request.path
|
||||
ServerLog.write("%s requested %s" % (request.getClientIP(), path), Silent)
|
||||
|
||||
#Responses:
|
||||
class AccessDenied(resource.Resource):
|
||||
isLeaf = True
|
||||
def render(self, request):
|
||||
ServerLog.write("%s got 403 when requesting \"%s\"" % (request.getClientIP(), request.path), Silent)
|
||||
|
||||
request.setResponseCode(403)
|
||||
return "403 - Access denied\nThis proxy is only for Flipnote Hatena for the DSi."
|
||||
AccessDenied = AccessDenied()
|
||||
class NotFound(resource.Resource):
|
||||
isLeaf = True
|
||||
def render(self, request):
|
||||
args = "&".join(("%s=%s" % (i, request.args[i][0]) for i in request.args))
|
||||
path = ("%s?%s" % (request.path, args)) if args else request.path
|
||||
|
||||
ServerLog.write("%s got 404 when requesting \"%s\"" % (request.getClientIP(), path), Silent)
|
||||
request.setResponseCode(404)
|
||||
return "404 - Not Found\nThis proxy is only for Flipnote Hatena for the DSi."
|
||||
NotFound = NotFound()
|
||||
|
||||
#Root structure:
|
||||
class Root(resource.Resource):#filters out non-hantena clients
|
||||
isLeaf = False
|
||||
def __init__(self):
|
||||
resource.Resource.__init__(self)
|
||||
|
||||
self.dsResource = ds()
|
||||
self.cssResource = static.File("hatenadir/css/")
|
||||
self.imagesResource = static.File("hatenadir/images/")
|
||||
def getChild(self, name, request):
|
||||
if "x-dsi-sid" not in request.getAllHeaders():
|
||||
return AccessDenied
|
||||
|
||||
if name == "ds":
|
||||
return self.dsResource
|
||||
elif name == "css":
|
||||
return self.cssResource
|
||||
elif name == "images":
|
||||
return self.imagesResource
|
||||
elif name == "":
|
||||
return self
|
||||
|
||||
#return NotFound
|
||||
return self
|
||||
def render(self, request):
|
||||
Log(request, "root")
|
||||
return "Welcome to hatena.pbsds.net!\nThis is in early stages, so please don't expect too much."
|
||||
class ds(resource.Resource):#child of Root
|
||||
isLeaf = False
|
||||
def __init__(self):
|
||||
resource.Resource.__init__(self)
|
||||
|
||||
self.region = UgoRoot()
|
||||
self.regions = ("v2-xx", "v2-eu", "v2-us", "v2-jp")
|
||||
def getChild(self, name, request):
|
||||
if name in self.regions:
|
||||
return self.region
|
||||
elif name == "":
|
||||
return self
|
||||
return NotFound
|
||||
def render(self, request):
|
||||
Log(request)
|
||||
return "ds desu"
|
||||
class UgoRoot(resource.Resource):#child of ds. (v2-xx)
|
||||
isLeaf = False
|
||||
def __init__(self):
|
||||
resource.Resource.__init__(self)
|
||||
|
||||
LoadHatenaStructure(self)
|
||||
def getChild(self, name, request):
|
||||
if name == "":
|
||||
return self
|
||||
return NotFound
|
||||
def render(self, request):
|
||||
Log(request, "ugoroot")
|
||||
return "UgoRoot desu"
|
||||
|
||||
#UgoRoot filestructure:
|
||||
class FileResource(resource.Resource):
|
||||
isLeaf = True
|
||||
def __init__(self, filepath, Store=False):
|
||||
resource.Resource.__init__(self)
|
||||
|
||||
self.Store = Store
|
||||
|
||||
if Store:
|
||||
f = open(filepath, "rb")
|
||||
self.file = f.read()
|
||||
f.close()
|
||||
else:
|
||||
self.file = filepath
|
||||
|
||||
self.html = filepath.split(".")[-1][:3] == "htm"
|
||||
def render(self, request):
|
||||
path = "/".join(request.path.split("/")[3:])
|
||||
Log(request, path)
|
||||
|
||||
if self.html:
|
||||
#request.responseHeaders.setRawHeaders('content-type', ['text/html'])
|
||||
pass
|
||||
else:
|
||||
request.responseHeaders.setRawHeaders('content-type', ['text/plain'])
|
||||
|
||||
if self.Store:
|
||||
return self.file
|
||||
else:
|
||||
#f = open(self.file, "rb")
|
||||
#ret = f.read()
|
||||
#f.close()
|
||||
#return ret
|
||||
|
||||
return static.File(self.file).render(request)
|
||||
class UGOXMLResource(resource.Resource):
|
||||
isLeaf = True
|
||||
def __init__(self, filepath):
|
||||
resource.Resource.__init__(self)
|
||||
|
||||
|
||||
self.ugofile = UGO().ReadXML(filepath, False)
|
||||
self.ugofile = self.ugofile.Pack()
|
||||
def render(self, request):
|
||||
path = "/".join(request.path.split("/")[3:])
|
||||
Log(request, path)
|
||||
|
||||
#page = int(request.args["page"][0]) if "page" in request.args else 1
|
||||
request.responseHeaders.setRawHeaders('content-type', ['text/plain'])
|
||||
return self.ugofile
|
||||
class FolderResource(resource.Resource):
|
||||
isLeaf = False
|
||||
def getChild(self, name, request):
|
||||
if name == "":
|
||||
return self
|
||||
return NotFound
|
||||
def render(self, request):
|
||||
path = "/".join(request.path.split("/")[3:])
|
||||
Log(request, path)
|
||||
return "This is a folder, but I'm to lazy to list the contents..."
|
||||
def LoadHatenaStructure(Resource, path="hatenadir/ds/v2-xx", root = True):
|
||||
for i in glob.glob("%s\*" % path):
|
||||
if os.path.isfile(i):
|
||||
filename = os.path.basename(i)
|
||||
filetype = filename.split(".")[-1].lower()
|
||||
|
||||
if filetype == "ugoxml":
|
||||
Resource.putChild(filename[:-3], UGOXMLResource(i))
|
||||
elif filetype == "py":
|
||||
try:
|
||||
#sys.path.append(os.path.abspath(os.path.dirname(i)))
|
||||
# #pyfile = __import__(filename[:-3])
|
||||
#pyfile = importlib.import_module(filename[:-3])
|
||||
#sys.path.pop(-1)
|
||||
#pyfile = imp.load_module(i)
|
||||
|
||||
pyfile = imp.load_source("pyfile", os.path.abspath(i))
|
||||
except ImportError as err:
|
||||
pyfile = None
|
||||
print "Error!"
|
||||
print "Failed to import the python file \"%s\"" % i
|
||||
print err
|
||||
|
||||
if pyfile:
|
||||
Resource.putChild(filename[:-3], pyfile.PyResource())
|
||||
elif filetype == "pyc":
|
||||
pass#ignore
|
||||
else:
|
||||
Resource.putChild(filename, FileResource(os.path.join(path, filename)))
|
||||
elif os.path.isdir(i):
|
||||
if os.path.basename(i)[:2] <> "__":
|
||||
folder = FolderResource()
|
||||
LoadHatenaStructure(folder, os.path.join(path, os.path.basename(i)), False)
|
||||
Resource.putChild(os.path.basename(i), folder)
|
||||
|
||||
#Flipnote handler:
|
||||
class Database:
|
||||
def __init__(self):
|
||||
#read:
|
||||
f = open("database/new_flipnotes.dat", "rb")#contains the newest 5000 flipnotes
|
||||
self.Newest = [tuple(i.split("\t")) for i in f.read().split("\n")]#[i] = [creatorID, filename]
|
||||
self.new = False#True when new flipnotes has been uploaded
|
||||
f.close()
|
||||
|
||||
self.Creator = {}#to store creator info updates before writing to disk. Creator[id][n] = [filename, views, stars, green stars, red stars, blue stars, purple stars, Channel]
|
||||
|
||||
reactor.callLater(60*3, self.flusher)
|
||||
atexit.register(self.write)
|
||||
|
||||
#to check if an update is neccesary:
|
||||
self.Views = 0
|
||||
self.Stars = 0
|
||||
def flusher(self):#Automatically flushes the files every 3 minutes and trims down memory usage
|
||||
reactor.callLater(60*3, self.flusher)
|
||||
|
||||
#trim newest:
|
||||
if len(self.Newest) > 5000:
|
||||
self.Newest = self.Newest[:5000]
|
||||
|
||||
self.write()
|
||||
def write(self):
|
||||
if self.new:
|
||||
f = open("database/new_flipnotes.dat", "wb")
|
||||
f.write("\n".join(("\t".join(i) for i in self.Newest)))
|
||||
f.close()
|
||||
self.new = False
|
||||
|
||||
for ID in self.Creator.keys():
|
||||
f = open("database/Creators/%s/flipnotes.dat" % ID, "wb")
|
||||
f.write("\n".join(("\t".join(map(str, i)) for i in self.Creator[ID])))
|
||||
f.close()
|
||||
del self.Creator[ID]
|
||||
#helpers:
|
||||
def FlipnotePath(self, CreatorID, filename):
|
||||
return "database/Creators/%s/%s" % (CreatorID, filename)
|
||||
def CreatorExists(self, CreatorID):
|
||||
return os.path.exists("database/Creators/" + CreatorID) or (CreatorID in self.Creator)
|
||||
def FlipnoteExists(self, CreatorID, filename):
|
||||
return os.path.exists("database/Creators/%s/%s.ppm" % (CreatorID, filename))
|
||||
#interface:
|
||||
def GetCreator(self, CreatorID, Load=False):#Load holds it in memory, use this when making changes or reading him often
|
||||
if CreatorID in self.Creator:
|
||||
return self.Creator[CreatorID]
|
||||
else:
|
||||
if not os.path.exists("database/Creators/" + CreatorID):
|
||||
return None
|
||||
|
||||
f = open("database/Creators/%s/flipnotes.dat" % CreatorID, "rb")
|
||||
ret = [i.split("\t") for i in f.read().split("\n")]
|
||||
f.close()
|
||||
|
||||
if Load:
|
||||
self.Creator[CreatorID] = ret
|
||||
|
||||
return ret
|
||||
def GetFlipnote(self, CreatorID, filename):#[filename, views, stars, green stars, red stars, blue stars, purple stars, Channel]
|
||||
for i in (self.GetCreator(CreatorID) or []):
|
||||
if i[0] == filename:
|
||||
return i
|
||||
return False
|
||||
def AddFlipnote(self, content, Channel=""):
|
||||
tmb = TMB().Read(content)
|
||||
if not tmb:
|
||||
return False
|
||||
|
||||
#CreatorID = tmb.Username
|
||||
CreatorID = tmb.EditorAuthorID
|
||||
filename = tmb.CurrentFilename[:-4]
|
||||
del tmb
|
||||
|
||||
if os.path.exists("database/Creators/%s/%s.ppm" % (CreatorID, filename)):#already exists
|
||||
return False
|
||||
|
||||
#add to database:
|
||||
self.new = True
|
||||
self.Newest.insert(0, (CreatorID, filename))
|
||||
|
||||
if not self.GetCreator(CreatorID, True):
|
||||
self.Creator[CreatorID] = [[filename, 0, 0, 0, 0, 0, 0, Channel]]
|
||||
else:
|
||||
self.Creator[CreatorID].append([filename, 0, 0, 0, 0, 0, 0, Channel])
|
||||
|
||||
#write flipnote to file:
|
||||
if not os.path.isdir("database/Creators/" + CreatorID):
|
||||
os.mkdir("database/Creators/" + CreatorID)
|
||||
f = open("database/Creators/%s/%s.ppm" % (CreatorID, filename), "wb")
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
return CreatorID, filename
|
||||
def AddView(self, CreatorID, filename):
|
||||
for i, flipnote in enumerate(self.GetCreator(CreatorID, True) or []):
|
||||
if flipnote[0] == filename:
|
||||
self.Creator[CreatorID][i][1] = int(flipnote[1]) + 1
|
||||
self.Views += 1
|
||||
return True
|
||||
return False
|
||||
def AddStar(self, Creator, filename, amount=1):
|
||||
for i, flipnote in enumerate(self.GetCreator(CreatorID, True) or []):
|
||||
if flipnote[0] == filename:
|
||||
self.Creator[CreatorID][i][2] = int(flipnote[2]) + amount
|
||||
self.Stars += 1
|
||||
return True
|
||||
return False
|
||||
Database = Database()
|
||||
|
||||
#when loading:
|
||||
def Setup():
|
||||
print "Setting up hatena...",
|
||||
root = Root()
|
||||
print "Done!"
|
||||
return root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user
