Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
#
2
# Licensed to the Apache Software Foundation (ASF) under one
3
# or more contributor license agreements. See the NOTICE file
4
# distributed with this work for additional information
5
# regarding copyright ownership. The ASF licenses this file
6
# to you under the Apache License, Version 2.0 (the
7
# "License"); you may not use this file except in compliance
8
# with the License. You may obtain a copy of the License at
9
#
10
#   http://www.apache.org/licenses/LICENSE-2.0
11
#
12
# Unless required by applicable law or agreed to in writing,
13
# software distributed under the License is distributed on an
14
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
# KIND, either express or implied. See the License for the
16
# specific language governing permissions and limitations
17
# under the License.
18
#
19
 
20
from cStringIO import StringIO
21
from struct import pack,unpack
22
from thrift.Thrift import TException
23
 
24
class TTransportException(TException):
25
 
26
  """Custom Transport Exception class"""
27
 
28
  UNKNOWN = 0
29
  NOT_OPEN = 1
30
  ALREADY_OPEN = 2
31
  TIMED_OUT = 3
32
  END_OF_FILE = 4
33
 
34
  def __init__(self, type=UNKNOWN, message=None):
35
    TException.__init__(self, message)
36
    self.type = type
37
 
38
class TTransportBase:
39
 
40
  """Base class for Thrift transport layer."""
41
 
42
  def isOpen(self):
43
    pass
44
 
45
  def open(self):
46
    pass
47
 
48
  def close(self):
49
    pass
50
 
51
  def read(self, sz):
52
    pass
53
 
54
  def readAll(self, sz):
55
    buff = ''
56
    have = 0
57
    while (have < sz):
58
      chunk = self.read(sz-have)
59
      have += len(chunk)
60
      buff += chunk
61
 
62
      if len(chunk) == 0:
63
        raise EOFError()
64
 
65
    return buff
66
 
67
  def write(self, buf):
68
    pass
69
 
70
  def flush(self):
71
    pass
72
 
73
# This class should be thought of as an interface.
74
class CReadableTransport:
75
  """base class for transports that are readable from C"""
76
 
77
  # TODO(dreiss): Think about changing this interface to allow us to use
78
  #               a (Python, not c) StringIO instead, because it allows
79
  #               you to write after reading.
80
 
81
  # NOTE: This is a classic class, so properties will NOT work
82
  #       correctly for setting.
83
  @property
84
  def cstringio_buf(self):
85
    """A cStringIO buffer that contains the current chunk we are reading."""
86
    pass
87
 
88
  def cstringio_refill(self, partialread, reqlen):
89
    """Refills cstringio_buf.
90
 
91
    Returns the currently used buffer (which can but need not be the same as
92
    the old cstringio_buf). partialread is what the C code has read from the
93
    buffer, and should be inserted into the buffer before any more reads.  The
94
    return value must be a new, not borrowed reference.  Something along the
95
    lines of self._buf should be fine.
96
 
97
    If reqlen bytes can't be read, throw EOFError.
98
    """
99
    pass
100
 
101
class TServerTransportBase:
102
 
103
  """Base class for Thrift server transports."""
104
 
105
  def listen(self):
106
    pass
107
 
108
  def accept(self):
109
    pass
110
 
111
  def close(self):
112
    pass
113
 
114
class TTransportFactoryBase:
115
 
116
  """Base class for a Transport Factory"""
117
 
118
  def getTransport(self, trans):
119
    return trans
120
 
121
class TBufferedTransportFactory:
122
 
123
  """Factory transport that builds buffered transports"""
124
 
125
  def getTransport(self, trans):
126
    buffered = TBufferedTransport(trans)
127
    return buffered
128
 
129
 
130
class TBufferedTransport(TTransportBase,CReadableTransport):
131
 
132
  """Class that wraps another transport and buffers its I/O."""
133
 
134
  DEFAULT_BUFFER = 4096
135
 
136
  def __init__(self, trans):
137
    self.__trans = trans
138
    self.__wbuf = StringIO()
139
    self.__rbuf = StringIO("")
140
 
141
  def isOpen(self):
142
    return self.__trans.isOpen()
143
 
144
  def open(self):
145
    return self.__trans.open()
146
 
147
  def close(self):
148
    return self.__trans.close()
149
 
150
  def read(self, sz):
151
    ret = self.__rbuf.read(sz)
152
    if len(ret) != 0:
153
      return ret
154
 
155
    self.__rbuf = StringIO(self.__trans.read(max(sz, self.DEFAULT_BUFFER)))
156
    return self.__rbuf.read(sz)
157
 
158
  def write(self, buf):
159
    self.__wbuf.write(buf)
160
 
161
  def flush(self):
162
    out = self.__wbuf.getvalue()
163
    # reset wbuf before write/flush to preserve state on underlying failure
164
    self.__wbuf = StringIO()
165
    self.__trans.write(out)
166
    self.__trans.flush()
167
 
168
  # Implement the CReadableTransport interface.
169
  @property
170
  def cstringio_buf(self):
171
    return self.__rbuf
172
 
173
  def cstringio_refill(self, partialread, reqlen):
174
    retstring = partialread
175
    if reqlen < self.DEFAULT_BUFFER:
176
      # try to make a read of as much as we can.
177
      retstring += self.__trans.read(self.DEFAULT_BUFFER)
178
 
179
    # but make sure we do read reqlen bytes.
180
    if len(retstring) < reqlen:
181
      retstring += self.__trans.readAll(reqlen - len(retstring))
182
 
183
    self.__rbuf = StringIO(retstring)
184
    return self.__rbuf
185
 
186
class TMemoryBuffer(TTransportBase, CReadableTransport):
187
  """Wraps a cStringIO object as a TTransport.
188
 
189
  NOTE: Unlike the C++ version of this class, you cannot write to it
190
        then immediately read from it.  If you want to read from a
191
        TMemoryBuffer, you must either pass a string to the constructor.
192
  TODO(dreiss): Make this work like the C++ version.
193
  """
194
 
195
  def __init__(self, value=None):
196
    """value -- a value to read from for stringio
197
 
198
    If value is set, this will be a transport for reading,
199
    otherwise, it is for writing"""
200
    if value is not None:
201
      self._buffer = StringIO(value)
202
    else:
203
      self._buffer = StringIO()
204
 
205
  def isOpen(self):
206
    return not self._buffer.closed
207
 
208
  def open(self):
209
    pass
210
 
211
  def close(self):
212
    self._buffer.close()
213
 
214
  def read(self, sz):
215
    return self._buffer.read(sz)
216
 
217
  def write(self, buf):
218
    self._buffer.write(buf)
219
 
220
  def flush(self):
221
    pass
222
 
223
  def getvalue(self):
224
    return self._buffer.getvalue()
225
 
226
  # Implement the CReadableTransport interface.
227
  @property
228
  def cstringio_buf(self):
229
    return self._buffer
230
 
231
  def cstringio_refill(self, partialread, reqlen):
232
    # only one shot at reading...
233
    raise EOFError()
234
 
235
class TFramedTransportFactory:
236
 
237
  """Factory transport that builds framed transports"""
238
 
239
  def getTransport(self, trans):
240
    framed = TFramedTransport(trans)
241
    return framed
242
 
243
 
244
class TFramedTransport(TTransportBase, CReadableTransport):
245
 
246
  """Class that wraps another transport and frames its I/O when writing."""
247
 
248
  def __init__(self, trans,):
249
    self.__trans = trans
250
    self.__rbuf = StringIO()
251
    self.__wbuf = StringIO()
252
 
253
  def isOpen(self):
254
    return self.__trans.isOpen()
255
 
256
  def open(self):
257
    return self.__trans.open()
258
 
259
  def close(self):
260
    return self.__trans.close()
261
 
262
  def read(self, sz):
263
    ret = self.__rbuf.read(sz)
264
    if len(ret) != 0:
265
      return ret
266
 
267
    self.readFrame()
268
    return self.__rbuf.read(sz)
269
 
270
  def readFrame(self):
271
    buff = self.__trans.readAll(4)
272
    sz, = unpack('!i', buff)
273
    self.__rbuf = StringIO(self.__trans.readAll(sz))
274
 
275
  def write(self, buf):
276
    self.__wbuf.write(buf)
277
 
278
  def flush(self):
279
    wout = self.__wbuf.getvalue()
280
    wsz = len(wout)
281
    # reset wbuf before write/flush to preserve state on underlying failure
282
    self.__wbuf = StringIO()
283
    # N.B.: Doing this string concatenation is WAY cheaper than making
284
    # two separate calls to the underlying socket object. Socket writes in
285
    # Python turn out to be REALLY expensive, but it seems to do a pretty
286
    # good job of managing string buffer operations without excessive copies
287
    buf = pack("!i", wsz) + wout
288
    self.__trans.write(buf)
289
    self.__trans.flush()
290
 
291
  # Implement the CReadableTransport interface.
292
  @property
293
  def cstringio_buf(self):
294
    return self.__rbuf
295
 
296
  def cstringio_refill(self, prefix, reqlen):
297
    # self.__rbuf will already be empty here because fastbinary doesn't
298
    # ask for a refill until the previous buffer is empty.  Therefore,
299
    # we can start reading new frames immediately.
300
    while len(prefix) < reqlen:
301
      self.readFrame()
302
      prefix += self.__rbuf.getvalue()
303
    self.__rbuf = StringIO(prefix)
304
    return self.__rbuf
305
 
306
 
307
class TFileObjectTransport(TTransportBase):
308
  """Wraps a file-like object to make it work as a Thrift transport."""
309
 
310
  def __init__(self, fileobj):
311
    self.fileobj = fileobj
312
 
313
  def isOpen(self):
314
    return True
315
 
316
  def close(self):
317
    self.fileobj.close()
318
 
319
  def read(self, sz):
320
    return self.fileobj.read(sz)
321
 
322
  def write(self, buf):
323
    self.fileobj.write(buf)
324
 
325
  def flush(self):
326
    self.fileobj.flush()