source: orange/orange/addOnServer.py @ 8956:0abe1bb4e3ee

Revision 8956:0abe1bb4e3ee, 7.1 KB checked in by mitar, 3 years ago (diff)

Use new Orange website URL.

Line 
1from mod_python import apache
2from mod_python import util
3from mod_python.util import FieldStorage
4import os
5import codecs
6import glob
7import xml.dom.minidom
8import time
9import re
10import widgetParser
11import mimetypes
12from zipfile import ZipFile
13import fileutil
14
15def _reqArgs(req):
16    """
17    Returns a dictionary of name->value pairs for request's arguments and fields.
18    """
19    result = {}
20    data = FieldStorage(req, keep_blank_values=1)
21    for fieldName in data.keys():
22        fieldData = data[fieldName] 
23        if type(fieldData) is list:  # on POST requests if there is name collision between a parameter and a field
24            result[fieldName] = fieldData[-1].value
25        else:
26            result[fieldName] = fieldData.value
27    return result
28
29def _handlerMachine(req, args, repositoryDir):
30    # Orange Canvas is calling home and needs data!
31    (ok, cache) = _updateXml(repositoryDir)
32    req.content_type = 'application/xml; charset=utf-8'
33    if ok:
34        req.sendfile(os.path.join(repositoryDir, ".cache.xml"))
35        return apache.OK
36    else:
37        req.write(cache.toxml("UTF-8"))
38        return apache.OK
39
40#global cntr
41#cntr = 0
42
43def _logTmp(s):
44    import time
45    tmpf=open('/tmp/server%d.tmp' % os.getpid(), 'a')
46    tmpf.write('%s %s %s\n' % (time.strftime('%a, %d %b %Y %H:%M:%S', time.gmtime()), str(os.getpid()), s))
47    tmpf.close()
48
49def _handlerContent(req, args, repositoryDir):
50    # Documents, extracted from archive -- or a simple default page
51    #_logTmp("Got request for %s." % req.uri)
52    try:
53        suburi = req.uri.split(".py/", 1)
54        if len(suburi)>1:
55            if "/" in suburi[1]:   # we need to extract .oao contents
56                (oao, path) = suburi[1].split("/", 1)
57                path = re.sub(r"[\\/]+", "/", path)
58                path = re.sub(r"^/", "", path)
59                try:
60                    zipPath = os.path.join(repositoryDir, oao)
61                    global _zipCache
62                    if zipPath not in _zipCache:
63                        _zipCache[zipPath] = ZipFile(open(zipPath, 'rb'))
64                    pack = _zipCache[zipPath]
65                    fileName = path.split("/")[-1]
66                   
67                    filelist = pack.namelist()
68                    if path not in filelist and "icon" in args:
69                        req.internal_redirect("/"+"/".join(suburi[0].split("/")[:-1])+"/Unknown.png")
70                        return apache.OK
71                    elif path not in filelist and "doc" in args:
72                        import orange_headfoot
73                        return orange_headfoot._handleStatic(req, "<head><title>Orange - Documentation not found</title></head><body>Sorry, the documentation you look for is not available.</body>")
74                    if fileName=="" or path not in filelist:
75                        if path[-1]=="/": path=path[:-1]
76                        indexPages = ["main.htm", "main.html", "index.html", "index.htm", "default.html", "default.htm"]
77                        for indexPage in indexPages:
78                            if path+"/"+indexPage in filelist:
79                                path = path+"/"+indexPage
80                                break
81                        if path not in filelist:
82                            return apache.HTTP_NOT_FOUND
83                        fileName = path.split("/")[-1]
84                   
85                    type = mimetypes.guess_type(fileName)[0]
86                    if not type:
87                        return apache.NO_CONTENT
88                    content = pack.read(path)
89                    open('/tmp/addons.tmp', 'a').write("%s: %s\n" % (path, type))
90                    if type.startswith("text/html"):
91                        try:
92                            import orange_headfoot
93                            return orange_headfoot._handleStatic(req, content)
94                        except Exception, e:
95                            pass
96                    req.content_type = type
97                    req.write(content)
98                    return apache.OK
99                except Exception, e:
100                    return apache.INTERNAL_ERROR
101            else:
102                return apache.DECLINED
103        else:
104#            content = """<!doctype html>
105#            <html>
106#              <head>
107#                <title>Orange Add-on Repository</title>
108#              </head>
109#              <body><h1>Orange Add-on Repository %s</h1>
110#                <p>This is an <a href="http://orange.biolab.si">Orange</a> add-on repository. Would you like to <a href="upload.html">upload</a> new add-ons?</p>
111#              </body>
112#            </html>""" % req.uri
113#            try:
114#                import orange_headfoot
115#                orange_headfoot._handleStatic(req, content)
116#            except:
117#                req.content_type = 'text/html; charset=utf-8'
118#                req.write(content)
119#                return apache.OK
120            util.redirect(req, ".")
121    finally:
122        pass           
123
124def handler(req):
125    repositoryDir = os.path.dirname(req.filename)
126    args = _reqArgs(req)
127    return (_handlerMachine if "machine" in args else _handlerContent) (req, args, repositoryDir)
128
129
130
131_addOnsInCache = {}
132_zipCache = {}
133globals().update( {"_addOnsInCache": _addOnsInCache, "_zipCache": _zipCache} )
134
135def _addOnsInRepo(repositoryDir):
136    result = {}
137    for addOn in glob.glob(os.path.join(repositoryDir, "*.oao")):
138        if os.path.isfile(addOn):
139            fileTime = os.stat(addOn).st_mtime
140            result[addOn] = fileTime
141    return result
142
143def _updateXml(repositoryDir, returnCachedDoc=False):
144    addOnsInRepo = _addOnsInRepo(repositoryDir)
145    cacheFile = os.path.join(repositoryDir, ".cache.xml")
146    global _addOnsInCache
147    if (repositoryDir not in _addOnsInCache) or (addOnsInRepo != _addOnsInCache[repositoryDir]) or (not os.path.isfile(cacheFile)):
148        impl = xml.dom.minidom.getDOMImplementation()
149        cacheDoc = impl.createDocument(None, "OrangeAddOnRepository", None)
150        xmlRepo = cacheDoc.documentElement
151        for addOn in addOnsInRepo.keys():
152            try:
153                pack = ZipFile(addOn, 'r')
154                try:
155                    manifest = fileutil._zip_open(pack, 'addon.xml')
156                    addOnXmlDoc = xml.dom.minidom.parse(manifest)
157                    addOnXml = addOnXmlDoc.documentElement
158                    addOnXml.setAttribute("filename", os.path.split(addOn)[1])
159                    addOnXml.appendChild(widgetParser.widgetsXml(pack))   # Temporary: this should be done at upload.
160                    addOnXml.normalize()
161                    xmlRepo.appendChild(addOnXml)
162                finally:
163                    pack.close()
164            except Exception, e:
165                xmlRepo.appendChild(cacheDoc.createComment("Ignoring add-on %s: %s" % (addOn, e)))
166        try:
167            cacheDoc.writexml(codecs.open(cacheFile, 'w', "utf-8"), encoding="UTF-8")
168            _addOnsInCache[repositoryDir] = addOnsInRepo
169            return (True, cacheDoc)
170        except Exception, e:
171            print "Cannot write add-on cache! %s" % e
172            return (False, cacheDoc)
173    return (True, None if not returnCachedDoc else xml.dom.minidom.parse(open(cacheFile, 'r')))
Note: See TracBrowser for help on using the repository browser.