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