Package flumotion :: Package component :: Package misc :: Package httpserver :: Package httpcached :: Module resource_manager
[hide private]

Source Code for Module flumotion.component.misc.httpserver.httpcached.resource_manager

  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 errno 
 23   
 24  from twisted.internet import defer 
 25   
 26  from flumotion.common import log 
 27   
 28  from flumotion.component.misc.httpserver import fileprovider 
 29  from flumotion.component.misc.httpserver import cachestats 
 30   
 31  LOG_CATEGORY = "resource-manager" 
 32   
 33   
 34  errnoLookup = {errno.ENOENT: fileprovider.NotFoundError, 
 35                 errno.EISDIR: fileprovider.CannotOpenError, 
 36                 errno.EACCES: fileprovider.AccessError} 
 37   
 38   
39 -class DataSource(object):
40 """ 41 Base class for all resources data source. 42 """ 43 44 url = None 45 identifier = None 46 mimeType = None 47 mtime = None 48 size = None 49
50 - def read(self, offset, size):
51 raise NotImplementedError()
52
53 - def close(self):
54 raise NotImplementedError()
55 56
57 -class ResourceManager(log.Loggable):
58 """ 59 Provide file-like resources for URLs. 60 """ 61 62 logCategory = LOG_CATEGORY 63
64 - def __init__(self, strategy, stats):
65 self.strategy = strategy 66 self.stats = stats
67
68 - def getResourceFor(self, url):
69 self.debug("Resource requested with %s", url) 70 71 stats = cachestats.RequestStatistics(self.stats) 72 73 d = defer.Deferred() 74 d.addCallback(self.strategy.getSourceFor, stats) 75 d.addCallback(Resource, stats) 76 77 d.callback(url) 78 79 return d
80 81
82 -class Resource(object):
83 """ 84 Offers a file-like interface of a data source. 85 Handle errors and asynchronous readings and file offset. 86 """ 87
88 - def __init__(self, source, stats):
89 self._open(source) 90 self._offset = 0 91 self._reading = False 92 self.stats = stats
93
94 - def getMimeType(self):
95 return self.mimeType
96
97 - def getmtime(self):
98 return self._source.mtime
99
100 - def getsize(self):
101 return self._source.size
102
103 - def tell(self):
104 return self._offset
105
106 - def seek(self, offset):
107 self._check() 108 self._offset = offset
109
110 - def read(self, size):
111 self._check() 112 assert not self._reading, "Simultaneous read not supported" 113 try: 114 d = self._source.read(self._offset, size) 115 if isinstance(d, defer.Deferred): 116 self._reading = True 117 return d.addCallback(self._cbUpdateOffset) 118 self._offset += len(d) 119 return defer.succeed(d) 120 except IOError, e: 121 cls = errnoLookup.get(e.errno, fileprovider.FileError) 122 return defer.fail(cls("Failed to read data: %s", str(e))) 123 except: 124 return defer.fail()
125
126 - def produce(self, consumer, fromOffset=None):
127 """ 128 Returns a producer that produce data from the specified position 129 or from the current position if None is specified. 130 Can return None if a producer cannot be provided or is not convenient. 131 """ 132 self._check() 133 return self._source.produce(consumer, fromOffset or self._offset)
134
135 - def close(self):
136 self._check() 137 self._source.close() 138 self._source = None
139
140 - def getLogFields(self):
141 return self.stats.getLogFields()
142 143 ### Protected Methods ### 144
145 - def _check(self):
146 if self._source is None: 147 raise fileprovider.FileClosedError("File Closed")
148
149 - def _open(self, source):
150 self._source = source 151 self.mimeType = source.mimeType
152 153 ### Private Methods ### 154
155 - def _cbUpdateOffset(self, data):
156 self._reading = False 157 self._offset += len(data) 158 return data
159