source: trunk/src/testing/bin/fileServer/fileServer.py @ 4

Revision 4, 31.0 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1#!/usr/bin/env python
2############################################################################
3#
4# -= FileViewer =-
5#
6# FileServer - receives, provides and organizes multimedia files for use with SAGE
7#
8# Copyright (C) 2005 Electronic Visualization Laboratory,
9# University of Illinois at Chicago
10#
11# All rights reserved.
12#
13# Redistribution and use in source and binary forms, with or without
14# modification, are permitted provided that the following conditions are met:
15#
16#  * Redistributions of source code must retain the above copyright
17#    notice, this list of conditions and the following disclaimer.
18#  * Redistributions in binary form must reproduce the above
19#    copyright notice, this list of conditions and the following disclaimer
20#    in the documentation and/or other materials provided with the distribution.
21#  * Neither the name of the University of Illinois at Chicago nor
22#    the names of its contributors may be used to endorse or promote
23#    products derived from this software without specific prior written permission.
24#
25# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36#
37# Direct questions, comments etc about FileViewer to www.evl.uic.edu/cavern/forum
38#
39# Author: Ratko Jagodic
40#
41############################################################################
42 
43import os, base64, os.path, socket, shutil, sys, SocketServer, wx, stat, urllib
44from SimpleXMLRPCServer import *
45from threading import Thread
46from time import asctime, time
47import makeThumbs
48
49# miscellaneous stuff (3rd party supporting tools)
50sys.path.append("misc")  #so that we can import packages from "misc" folder
51from imsize import imagesize  # reads the image header and gets the size from it
52import mmpython
53import countPDFpages
54
55# a shortcut
56opj = os.path.join
57
58# for loading the sagePath helper file
59sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
60from sagePath import getUserPath, getPath
61
62
63## some globals defining the environment
64SCRIPT_PATH = sys.path[0]
65CONFIG_FILE = getPath("fileServer", "fileServer.conf")
66CACHE_DIR = getUserPath("fileServer", "file_server_cache")
67FILES_DIR = opj(SCRIPT_PATH, "file_library")
68REDIRECT = False
69THUMB_DIR = opj(FILES_DIR, "thumbnails")
70RUN_SERVER = True
71
72## holds information about the types that we support (read from the config file)
73dirHash = {}
74viewers = {}
75types = {}
76
77
78def ParseConfigFile():
79    global FILES_DIR
80    global THUMB_DIR
81    global dirHash
82    global types
83    global viewers
84
85    # reinitialize everything
86    FILES_DIR = ""
87    THUMB_DIR = ""
88    dirHash = {}
89    types = {}
90    viewers = {}
91
92    # read the config file
93    f = open(CONFIG_FILE, "r")
94    for line in f:
95        line = line.strip()
96        if line.startswith("FILES_DIR"):
97            FILES_DIR = line.split("=")[1].strip()
98            if not os.path.isabs(FILES_DIR):
99                FILES_DIR = getUserPath("fileServer", FILES_DIR)
100            FILES_DIR = os.path.realpath(FILES_DIR)  #expand any symbolic links in the library directory
101            THUMB_DIR = opj(FILES_DIR, "thumbnails")
102        elif line.startswith("type:"):
103            line = line.split(":",1)[1]
104            (type, extensions) = line.split("=")
105            types[type.strip()] = extensions.strip().split(" ")
106            dirHash[type.strip()] = opj(FILES_DIR, type.strip())
107        elif line.startswith("app:"):
108            line = line.split(":", 1)[1].strip()
109            (type, app) = line.split("=")
110            tpl = app.strip().split(" ", 1)
111            if len(tpl) == 1:  params = ""
112            else:  params = tpl[1].strip()
113            app = tpl[0].strip()
114            viewers[type.strip()] = (app, params)
115    f.close()
116
117
118    # create the folders first if they dont exist
119    if not os.path.isdir(FILES_DIR):
120        os.makedirs(FILES_DIR)
121    if not os.path.isdir(CACHE_DIR):
122        os.makedirs(CACHE_DIR)
123    for type, typeDir in dirHash.items():
124        if not os.path.isdir( ConvertPath(typeDir) ):
125            os.makedirs(typeDir)
126        if not os.path.isdir( ConvertPath( opj(typeDir, "Trash")) ):
127            os.makedirs( opj(typeDir, "Trash") )
128    if not os.path.isdir(THUMB_DIR):
129        os.makedirs(THUMB_DIR)
130
131
132
133# convert the path between the systems (Windows vs. Linux/Mac)
134def ConvertPath(path):
135    return apply(opj, tuple(path.split('\\')))
136
137
138
139
140
141import traceback as tb
142from SocketServer import ThreadingTCPServer, StreamRequestHandler
143
144
145
146class Listener(ThreadingTCPServer):
147    """ the main server listening for connections from HWCapture """
148   
149    allow_reuse_address = True
150    request_queue_size = 2
151   
152    def __init__(self, port, onMsgCallback, fileServer):
153        self.onMsgCallback = onMsgCallback
154        self.fileServer = fileServer
155        ThreadingTCPServer.__init__(self, ('', int(port)), SingleFileUpload)
156        self.socket.settimeout(0.5)
157
158
159    def serve_forever(self):
160        while RUN_SERVER:
161            try:
162                self.handle_request()
163            except socket.timeout:
164                pass
165            except KeyboardInterrupt:
166                break
167            except:
168                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
169                break
170 
171
172class SingleFileUpload(StreamRequestHandler):     
173    """ one of these per file upload """
174
175   
176    def handle(self):
177        """ this is where we parse the incoming messages """
178        self.request.settimeout(0.5)  # so that we can quit properly
179
180        # read the header
181        header = self.rfile.readline().strip()
182        if len(header) == 0:
183            return
184        (fileName, previewWidth, previewHeight, fileSize) = header.strip().split()
185        previewSize = (int(previewWidth), int(previewHeight))
186        fileSize = int(fileSize)
187       
188        # make sure the filename is ok
189        fileName = os.path.basename(fileName)   # strip any directory and just keep the filename (for security reasons)
190        fileType = self.server.fileServer.GetFileType(fileName)
191        if not fileType:
192            return #dont allow upload of anything that doesn't have an extension
193       
194        # make the file
195        fullPath = opj(dirHash[fileType], fileName)
196        try:
197            f=open(fullPath, "wb")
198        except:
199            WriteLog("Cannot create file (have write permissions?):" + filePath)
200            return
201
202        bytesRead = 0
203        while RUN_SERVER and bytesRead < fileSize:
204            try:
205                line = self.rfile.readline()
206                if not line:   # readline doesn't fail when socket is closed... it returns an empty string
207                    f.close()
208                    os.remove(fullPath)
209                    break
210                   
211                bytesRead+=len(line)
212                if bytesRead > fileSize:
213                    line = line.rstrip()   # remove the newline char at the end of transmission
214                f.write(line)
215               
216            except socket.timeout:
217                continue
218            except:
219                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
220                f.close()
221                os.remove(fullPath)
222                break
223        else:
224            f.flush()
225            f.close()
226
227            # tell the client that all went well
228            self.wfile.write("1") 
229           
230            # make the preview if necessary and everything went well
231            self.server.onMsgCallback(fileName, previewSize)
232
233
234
235
236
237
238
239
240class FileLibrary:
241    def __init__(self):
242        ParseConfigFile()
243
244        # start the server that will accept the file data
245        self.fServer = Listener(8802, self.__MakePreview, self)
246        fServerThread = Thread(target=self.fServer.serve_forever)
247        fServerThread.start()
248
249
250        ### used by clients to test the connection with the server
251    def TestConnection(self):
252        return (FILES_DIR, 0)
253
254
255         ### gets the file info:
256        ### full path, file type, application info, size (for images...), file size
257    def GetFileInfo(self, filename, fileSize=-1, path=None):
258        try:
259            ParseConfigFile()
260            fileType = self.GetFileType(filename)
261            size = (-1, -1)
262            fileExists = False
263
264            if fileType:  #is file even supported
265                appName = viewers[fileType][0]
266                params = viewers[fileType][1]
267                if path == None:  # the user dropped a new file on there
268                    fullPath = opj(self.__GetFilePath(fileType), filename)  # return a default path if not passed in
269                    res = self.__FileAlreadyThere(filename, fileType, fileSize)
270                    if res:  #if the file was found it will return its directory
271                        if fileType == "image":   #if the file is an image, return its size
272                            try:
273                                imsize = imagesize(fullPath)
274                                size = (imsize[1], imsize[0])
275                            except:
276                                size = (-1,-1)
277
278                        fullPath = opj(res, filename)  #the path of the found file
279                        fileExists = True
280                       
281                elif not self.__LegalPath(path):
282                    return False
283                else:             # the user is trying to show an existing file
284                    path = ConvertPath(path)
285                    fullPath = opj(path, filename)
286                    ## get the image size... FIX later (remove)
287                    if os.path.isfile(fullPath):
288                        fileExists = True
289                        if fileType == "image":   #if the file is an image, return its size
290                            try:
291                                imsize = imagesize(fullPath)
292                                size = (imsize[1], imsize[0])
293                            except:
294                                size = (-1,-1)
295                return (fileType, size, fullPath, appName, params, fileExists)
296            else:
297                return False  #file type not supported
298        except:
299            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
300            return False
301
302
303        ### gets the metadata information about the file
304    def GetMetadata(self, fullPath):
305        fullPath = ConvertPath(fullPath)
306        if not self.__LegalPath(fullPath):
307            return False
308
309        try:
310            fileType = self.GetFileType(fullPath)
311            if not fileType:
312                return False
313            elif fileType == "pdf":    # for pdfs
314                return "Pages: "+str(countPDFpages.getPDFPageCount(fullPath))
315            else:                      # for all other types
316                metadata = mmpython.parse(fullPath)
317                if metadata:   # metadata extracted successfully
318                    return unicode(metadata).encode('latin-1', 'replace')
319                else:
320                    return False
321        except:
322            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
323            return False
324       
325
326        ### construct a hash of all the files keyed by the directory in which the files
327        ### are and return it
328    def GetFiles(self):
329        ParseConfigFile()
330        numDirs = 0
331        numFiles = 0
332       
333        fileHash = {}
334        for fileType in dirHash.iterkeys():
335            fileHash[fileType] = self.__TraverseDir( self.__GetFilePath(fileType), fileType )
336        return fileHash
337   
338
339        ### deletes a folder and all files and dirs in it
340    # FIX to delete the thumbnails for all the images in this folder
341    def DeleteFolder(self, fullPath):
342        try:
343            if self.__LegalPath(fullPath):  # prevent users from deleting anything
344                shutil.rmtree(ConvertPath(fullPath))
345                return True
346            else:
347                return False
348        except:
349            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
350            return False
351
352
353        ### makes a new folder
354    def NewFolder(self, fullPath):
355        try:
356            if self.__LegalPath(fullPath):  # prevent users from deleting anything
357                os.mkdir(ConvertPath(fullPath))
358                self.__SetWritePermissions(ConvertPath(fullPath))
359                return True
360            else:
361                return False
362        except:
363            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
364            return False
365
366
367        ### move the file to Trash
368    def DeleteFile(self, fullPath):
369        try:
370            fullPath = ConvertPath(fullPath)
371            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
372                return False
373            fileType = self.GetFileType(fullPath)
374            if not fileType:  # no extension so don't allow deletion
375                return False
376
377            trashPath = opj( opj(self.__GetFilePath(fileType), "Trash"), os.path.split(fullPath)[1] )
378            self.MoveFile( fullPath, trashPath )
379            return True
380       
381        except:
382            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
383            return False
384
385
386        ### deletes the file from the library (also deletes it's thumbnail preview if it exists)
387    def DeleteFilePermanently(self, fullPath):
388        try:
389            fullPath = ConvertPath(fullPath)
390            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
391                return False
392            fileType = self.GetFileType(fullPath)
393            if not fileType:  # no extension so don't allow deletion
394                return False
395
396            previewPath = self.__GetPreviewName(fullPath)
397            if os.path.isfile(fullPath): # prevent users from deleting anything
398                os.remove( fullPath )      #remove the file itself
399                dxtFilePath = fullPath.rstrip(os.path.splitext(fullPath)[1])+".dxt"
400                if os.path.isfile(dxtFilePath):
401                    os.remove( dxtFilePath )  # remove the dxt file if it exists
402            if os.path.isfile( previewPath ):
403                os.remove( previewPath )  #remove its preview thumbnail
404            return True
405        except:
406            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
407            return False
408
409
410        ### moves the file from one directory to another
411    def MoveFile(self, oldFullPath, newFullPath):
412        oldFullPath = ConvertPath(oldFullPath)
413        newFullPath = ConvertPath(newFullPath)
414        if not self.__LegalPath(oldFullPath, newFullPath):  # restrict the movement to the FILES_DIR
415            return False
416        if os.path.isfile(oldFullPath):
417            try:
418                shutil.move(oldFullPath, newFullPath)
419                oldDxtFilePath = oldFullPath.rstrip(os.path.splitext(oldFullPath)[1])+".dxt"
420                newDxtFilePath = newFullPath.rstrip(os.path.splitext(newFullPath)[1])+".dxt"
421                if os.path.isfile(oldDxtFilePath):
422                    shutil.move(oldDxtFilePath, newDxtFilePath)
423                return True
424            except:
425                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
426                return False
427        else:
428            return False
429
430
431        ### accepts a file encoded as a base64 string and puts it in
432        ### the default directory for that file type
433    def UploadFile(self, name, data, previewSize=(150, 150)):
434        name = os.path.basename(name)   # strip any directory and just keep the filename (for security reasons)
435        fileType = self.GetFileType(name)
436        if not fileType:
437            return False  #dont allow upload of anything that doesn't have an extension
438        try:
439            # write the file
440            f=open( opj(dirHash[fileType], name), "wb")
441            f.write( base64.decodestring(data) )
442            f.close()
443            del data
444
445            self.__MakePreview(name, previewSize)
446
447            return True
448        except:
449            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
450            return False
451
452
453    def UploadLink(self, url):
454        name = os.path.basename(url)   # strip any directory and just keep the filename (for security reasons)
455        fileType = self.GetFileType(name)
456        if not fileType:
457            return False  #dont allow upload of anything that doesn't have an extension
458
459        try:
460            filename, headers = urllib.urlretrieve(url, opj(dirHash[fileType], name))
461            return True
462        except:
463            return False
464       
465
466        ### looks if there is a preview already saved... if not, create one and send it back
467    def GetPreview(self, fullPath, previewSize=(150,150)):
468        try:
469            res = self.MakeThumbnail(fullPath)
470            if res:
471                return (self.__ReadFile(res), True)
472            else:
473                return False
474        except:
475            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
476            return False
477
478       
479##         fullPath = ConvertPath(fullPath)
480##         if not self.__LegalPath(fullPath):
481##             return False
482##         fileType = self.GetFileType(fullPath)
483
484##         try:
485##             if fileType != "image" or not os.path.isfile(fullPath):
486##                 return False
487##             previewPath = self.__GetPreviewName(fullPath)
488##             wxImageType = self.__GetWxBitmapType(os.path.basename(fullPath))
489##             if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it
490##                 if wxImageType:               # is writing this file type supported?
491##                     im = wx.Image(fullPath)  # read the original image
492##                     if not im.Ok():   
493##                         return False         # the image is probably corrupted
494##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
495##                     im.SaveFile(previewPath, wxImageType)    # save it back to a file
496##                     self.__SetWritePermissions(previewPath)
497##                 else:     #if writing is not supported, try and read it and resize it on the fly
498##                     im = wx.Image(fullPath)  # read the original image
499##                     if not im.Ok():   
500##                         return False         # the image is probably corrupted
501##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
502##                     data = preview.GetData()
503##                     return (base64.encodestring(data), False)   #return the pixels themselves (isBinary=False)
504           
505##             return (self.__ReadFile(previewPath), True)
506##         except:
507##             WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
508##             return False
509
510
511    def MakeThumbnail(self, fullPath):
512        fullPath = ConvertPath(fullPath)
513        if not self.__LegalPath(fullPath):
514            return False
515        fileType = self.GetFileType(fullPath)
516       
517        try:
518            if not os.path.isfile(fullPath):
519                return False
520
521            previewPath = self.__GetPreviewName(fullPath)
522            if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it
523                makeThumbs.makeThumbnail(fullPath, fileType, previewPath)
524                if not os.path.isfile(previewPath):
525                    return False
526               
527            return previewPath
528        except:
529            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]))
530            return False
531
532
533
534        ### get the file ready for loading by the app on the "host" machine
535    def PrepareFile(self, fullPath, host):
536        if not self.__LegalPath(fullPath):
537            return False
538       
539        # make the connection with the remote FileServer
540        fileServer = xmlrpclib.ServerProxy("http://"+str(host)+":8800")
541
542        try:
543            # if the file exists already, there's no need to transfer it
544            filePath = fileServer.FileExists(fullPath, os.stat(fullPath).st_size)
545        except:
546            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
547            return False
548        if filePath:
549            return filePath  # if the file is already cached, just send the path back
550        else:
551            try:
552                # file is not cached so read it and send it to the remote FileServer
553                fileData = self.__ReadFile(fullPath)
554            except:
555                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
556                return False
557            else:
558                return fileServer.PutFile(os.path.basename(fullPath), fileData)
559 
560
561        ### gets the extension of the file that was passed in
562    def GetFileType(self, thefile):
563        try:
564            filename = os.path.basename( thefile )
565            extension = os.path.splitext(filename)[1].lower()
566            fileType = False
567            for fType in types.iterkeys():
568                    if extension in types[ fType ]:
569                        fileType = fType
570            return fileType
571        except:
572            return False
573       
574
575        ### does file exist in the cache already?? if not, someone will have to send it here
576    def FileExists(self, fullPath, size):
577        fullPath = ConvertPath(fullPath)
578        if os.path.isfile(fullPath):  # if the file server is on the same machine then we can
579            return fullPath           # just read the file directly from the file_library
580        filename = "_".join(os.path.basename(fullPath).split())
581        if filename == "":  # if it's a directory
582            return False
583        path = os.path.abspath( opj(CACHE_DIR, filename) )
584        if os.path.isfile(path) and os.stat(path).st_size==size:  #compare the sizes as well
585            return path
586        else:
587            return False
588
589
590        ### called by the remote FileServer to upload the file
591    def PutFile(self, filename, data):
592        try:
593            filename = "_".join(os.path.basename(filename).split()) # strip the directory and keep just the name (security reasons)
594            if filename == "":
595                return False
596            f=open( opj(CACHE_DIR, filename), "wb")
597            f.write( base64.decodestring(data) )
598            f.close()
599            self.__SetWritePermissions(opj(CACHE_DIR, filename))
600
601            del data
602            return os.path.abspath( opj(CACHE_DIR, filename) )  #return the path of the file to be passed to the app
603        except:
604            del data
605            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
606            return False
607
608
609        ### so that the server can be quit remotely
610    def Quit(self, var):
611        global RUN_SERVER
612        RUN_SERVER = False
613        return 1
614
615
616
617       
618
619#=======================================#
620########    Auxiliary methods    ########
621
622
623        ### constructs the preview name from the filename
624        ### preview name is: filename+fileSize+original_extension
625        ### (such as trees56893.jpg where 56893 is file size in bytes)
626    def __GetPreviewName(self, fullPath):
627        fileType = self.GetFileType(fullPath)
628
629        fileSize = os.stat(fullPath).st_size
630        (root, ext) = os.path.splitext( os.path.basename(fullPath) )
631        previewName = root+str(fileSize)+ext        #construct the preview name
632
633        # all the files have .jpg tacked onto the end
634        previewName += ".jpg"
635           
636        return opj( THUMB_DIR, previewName )
637
638
639    def __MakePreview(self, name, previewSize):
640        try:
641            wxImageType = self.__GetWxBitmapType(name)
642            if wxImageType:     # some types just cant be saved by wxPython
643                fileType = self.GetFileType(name)
644                # write the preview but name it with a filename and filesize so that they are unique
645                previewPath = self.__GetPreviewName(opj(dirHash[fileType], name))
646                im = wx.Image(opj(dirHash[fileType], name))  # read the original image
647
648                if im.Ok():  #the image may be corrupted...
649                    im.Rescale(previewSize[0], previewSize[1])        # resize it
650                    im.SaveFile(previewPath, wxImageType)    # save it back to a file
651                self.__SetWritePermissions(previewPath, opj(dirHash[fileType], name))
652        except:
653            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
654            pass    # no preview was saved... oh well
655
656
657
658        ### change the permission of the settings file to allow everyone to write to it
659    def __SetWritePermissions(self, *files):
660        for filePath in files:
661            try:
662                flags = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP | stat.S_IROTH
663                os.chmod(filePath, flags)
664            except:
665                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
666               
667       
668        ### reads a file and encodes it in a string (for transfer over the network)
669    def __ReadFile(self, fullPath):
670        f = open(fullPath, "rb")
671        fileData = base64.encodestring( f.read() )
672        f.close()
673        return fileData
674
675
676        ### looks through all the files of the same type
677        ### and figures out if the files is already there (optionally compare the file sizes as well)
678        ### if the same file is found, it will return its path
679    def __FileAlreadyThere(self, filename, fileType, size):
680        dirPath = self.__GetFilePath(fileType)
681        fileDir = False
682       
683        def LookForFile(dirPath, fileType, fileDir):
684            if fileDir:
685                return fileDir  #this will prevent the recursion to go on if we found a file (base case)
686            dirPath = ConvertPath(dirPath)
687            items = os.listdir(dirPath)
688            files = []
689            dirs = {}
690            for item in items:   #loop through all the items in this directory (files or dirs)
691                if os.path.isfile( opj(dirPath, item) ):  #is it a file
692                    if item.lower() == filename.lower():  #are their filenames equal
693                        if size==-1 or size==os.stat(opj(dirPath, item)).st_size:
694                            fileDir = dirPath
695                            return dirPath
696                elif os.path.isdir( opj(dirPath, item) ):  #is it a directory
697                    LookForFile( opj(dirPath, item), fileType, fileDir)  #if so, search in it
698            return False
699
700        return LookForFile(dirPath, fileType, fileDir)
701
702
703       ### recursively traverses the given directory
704       ### it return a tuple of (dir-path, list-of-dirs, files)
705    def __TraverseDir(self, dirPath, fileType):
706        dirPath = ConvertPath(dirPath)
707        items = os.listdir(dirPath)
708        files = []
709        dirs = {}
710        for item in items:
711            if os.path.isfile( opj(dirPath, item) ):
712                if self.GetFileType(item):  #if the file is supported, add it to the list, otherwise disregard it
713                    files.append(item)
714            elif os.path.isdir( opj(dirPath, item) ):
715                dirs[item] = self.__TraverseDir( opj(dirPath, item), fileType )
716        return (dirPath, dirs, files, fileType)
717
718
719       ### you pass it in a filename and it figures out the wx.BITMAP_TYPE and returns it
720    def __GetWxBitmapType(self, name):
721        ext = os.path.splitext(name)[1]
722        ext = ext.lower()
723        if ext==".jpg": return wx.BITMAP_TYPE_JPEG
724        elif ext==".png": return wx.BITMAP_TYPE_PNG
725        elif ext==".gif": return wx.BITMAP_TYPE_GIF
726        elif ext==".bmp": return wx.BITMAP_TYPE_BMP
727        elif ext==".pcx": return wx.BITMAP_TYPE_PCX
728        elif ext==".pnm": return wx.BITMAP_TYPE_PNM
729        elif ext==".tif": return wx.BITMAP_TYPE_TIF
730        elif ext==".tiff": return wx.BITMAP_TYPE_TIF
731        elif ext==".xpm": return wx.BITMAP_TYPE_XPM
732        elif ext==".ico": return wx.BITMAP_TYPE_ICO
733        elif ext==".cur": return wx.BITMAP_TYPE_CUR
734        else:
735            return False
736
737
738        ### gets the default path for a certain file type
739    def __GetFilePath(self, type=None):
740        if type == None:
741            return FILES_DIR
742        else:
743            return dirHash[type]
744
745
746
747        ### Checks whether all the paths are still within FILES_DIR (for security issues)
748    def __LegalPath(self, *pathList):
749        try:
750            normedPathList = []
751            normedPathList.append(FILES_DIR)
752            for path in pathList:
753                if path != "":
754                    normedPathList.append( os.path.normpath( os.path.realpath(path) ) )  # normalize all the paths (remove ../ kinda stuff)
755            return (os.path.commonprefix(normedPathList) == FILES_DIR)
756        except:
757            return False   #if anything fails, it's safer to assume that it's an illegal action
758
759
760    def __IsFolder(self, fullPath):
761        return (os.path.splitext(fullPath)[1] == '')
762   
763
764
765
766# to output all the error messages to a file
767def WriteLog(message):
768    try:
769        print message
770    except:
771        pass
772
773
774
775
776
777
778# a mix-in class for adding the threading support to the XMLRPC server
779class ThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
780    allow_reuse_address = True
781
782
783    # so that we can quit the server properly
784class MyServer(ThreadedXMLRPCServer):
785    def serve_forever(self):
786        while RUN_SERVER:
787            self.handle_request()
788   
789   
790
791
792def main(argv):
793
794    ## global REDIRECT   
795##     if len(argv) > 2:
796##         if "-v" in argv:
797##             REDIRECT = False
798##         else:
799
800##             # redirect all the output to nothing
801##             class dummyStream:
802##                 ''' dummyStream behaves like a stream but does nothing. '''
803##                 def __init__(self): pass
804##                 def write(self,data): pass
805##                 def read(self,data): pass
806##                 def flush(self): pass
807##                 def close(self): pass
808##             # and now redirect all default streams to this dummyStream:
809##             sys.stdout = dummyStream()
810##             sys.stderr = dummyStream()
811##             sys.stdin = dummyStream()
812##             sys.__stdout__ = dummyStream()
813##             sys.__stderr__ = dummyStream()
814##             sys.__stdin__ = dummyStream()
815
816
817    wx.InitAllImageHandlers()
818
819    # start the XMLRPC server
820    server = MyServer(("", 8800), SimpleXMLRPCRequestHandler, logRequests=False)
821    server.register_instance(FileLibrary())
822    server.serve_forever()
823
824
825
826if __name__ == '__main__':
827    import sys, os
828    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
829   
Note: See TracBrowser for help on using the repository browser.