Package flumotion :: Package component :: Package misc :: Package httpserver :: Module localprovider
[hide private]

Source Code for Module flumotion.component.misc.httpserver.localprovider

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_component_providers -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  import os 
 19  import stat 
 20  import errno 
 21   
 22  from twisted.internet import defer 
 23   
 24  from flumotion.common import log 
 25  from flumotion.component.misc.httpserver import fileprovider, localpath 
 26  from flumotion.component.misc.httpserver.fileprovider import FileError 
 27  from flumotion.component.misc.httpserver.fileprovider import FileClosedError 
 28   
 29  # os.SEEK_SET is not definied in python 2.4 
 30  SEEK_SET = 0 
 31   
 32  LOG_CATEGORY = "fileprovider-local" 
 33   
 34   
35 -class FileProviderLocalPlug(fileprovider.FileProviderPlug, log.Loggable):
36 """ 37 I am a plug that provide local files directly, 38 faking the file access is asynchronous. 39 """ 40 41 logcategory = LOG_CATEGORY 42
43 - def __init__(self, args):
44 props = args['properties'] 45 self._path = props.get('path', None)
46
47 - def startStatsUpdates(self, updater):
48 # No statistics for local file provider 49 pass
50
51 - def stopStatsUpdates(self):
52 pass
53
54 - def getRootPath(self):
55 if self._path is None: 56 return None 57 return LocalPath(self._path)
58 59
60 -class LocalPath(localpath.LocalPath):
61
62 - def open(self):
63 return LocalFile(self._path, self.mimeType)
64 65
66 -class LocalFile(fileprovider.File, log.Loggable):
67 """ 68 I offer a fake asynchronous wrapper around a synchronous file. 69 I'm not thread-safe, I should only be used to read small blocks 70 from a local file system and I don't support cloning. 71 """ 72 73 logCategory = LOG_CATEGORY 74 75 _errorLookup = {errno.ENOENT: fileprovider.NotFoundError, 76 errno.ENOTDIR: fileprovider.NotFoundError, 77 errno.EISDIR: fileprovider.CannotOpenError, 78 errno.EACCES: fileprovider.AccessError} 79 80 # Overriding parent class properties to become attribute 81 mimeType = None 82 83 # Default values 84 _file = None 85 _info = None 86
87 - def __init__(self, path, mimeType):
88 self._path = path 89 self.mimeType = mimeType 90 try: 91 self._file = open(path, 'rb') 92 self.debug("%s opened [fd %5d]", self, self._file.fileno()) 93 except IOError, e: 94 cls = self._errorLookup.get(e[0], FileError) 95 raise cls("Failed to open file '%s': %s" % (path, str(e))) 96 try: 97 self._info = os.fstat(self._file.fileno()) 98 except OSError, e: 99 cls = self._errorLookup.get(e[0], FileError) 100 raise cls("Failed to stat file '%s': %s" % (path, str(e)))
101
102 - def __str__(self):
103 return "<LocalFile '%s'>" % self._path
104
105 - def getsize(self):
106 if self._file is None: 107 raise FileClosedError("File closed") 108 # The size is not supposed to change over time 109 return self._info[stat.ST_SIZE]
110
111 - def getmtime(self):
112 if self._file is None: 113 raise FileClosedError("File closed") 114 # The modification time is not supposed to change over time 115 return self._info[stat.ST_MTIME]
116
117 - def tell(self):
118 if self._file is None: 119 raise FileClosedError("File closed") 120 try: 121 return self._file.tell() 122 except IOError, e: 123 cls = self._errorLookup.get(e[0], FileError) 124 raise cls("Failed to tell position in file '%s': %s" 125 % (self._path, str(e)))
126
127 - def seek(self, offset):
128 if self._file is None: 129 raise FileClosedError("File closed") 130 try: 131 self._file.seek(offset, SEEK_SET) 132 except IOError, e: 133 cls = self._errorLookup.get(e[0], FileError) 134 raise cls("Failed to seek in file '%s': %s" 135 % (self._path, str(e)))
136
137 - def read(self, size):
138 if self._file is None: 139 raise FileClosedError("File closed") 140 try: 141 data = self._file.read(size) 142 return defer.succeed(data) 143 except IOError, e: 144 cls = self._errorLookup.get(e[0], FileError) 145 return defer.fail(cls("Failed to read data from %s: %s" 146 % (self._path, str(e)))) 147 except: 148 return defer.fail()
149
150 - def close(self):
151 if self._file is not None: 152 try: 153 try: 154 self._file.close() 155 finally: 156 self._file = None 157 self._info = None 158 except IOError, e: 159 cls = self._errorLookup.get(e[0], FileError) 160 raise cls("Failed to close file '%s': %s" 161 % (self._path, str(e)))
162
163 - def __del__(self):
164 self.close()
165
166 - def getLogFields(self):
167 return {}
168