~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/medium.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006,2007 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
import os
28
28
import socket
29
29
import sys
 
30
 
30
31
from bzrlib import errors
31
 
from bzrlib.smart.protocol import SmartServerRequestProtocolOne
 
32
from bzrlib.smart.protocol import (
 
33
    REQUEST_VERSION_TWO,
 
34
    SmartServerRequestProtocolOne,
 
35
    SmartServerRequestProtocolTwo,
 
36
    )
32
37
 
33
38
try:
34
39
    from bzrlib.transport import ssh
66
71
        from sys import stderr
67
72
        try:
68
73
            while not self.finished:
69
 
                protocol = SmartServerRequestProtocolOne(self.backing_transport,
70
 
                                                         self._write_out)
71
 
                self._serve_one_request(protocol)
 
74
                server_protocol = self._build_protocol()
 
75
                self._serve_one_request(server_protocol)
72
76
        except Exception, e:
73
77
            stderr.write("%s terminating on exception %s\n" % (self, e))
74
78
            raise
75
79
 
 
80
    def _build_protocol(self):
 
81
        """Identifies the version of the incoming request, and returns an
 
82
        a protocol object that can interpret it.
 
83
 
 
84
        If more bytes than the version prefix of the request are read, they will
 
85
        be fed into the protocol before it is returned.
 
86
 
 
87
        :returns: a SmartServerRequestProtocol.
 
88
        """
 
89
        # Identify the protocol version.
 
90
        bytes = self._get_line()
 
91
        if bytes.startswith(REQUEST_VERSION_TWO):
 
92
            protocol_class = SmartServerRequestProtocolTwo
 
93
            bytes = bytes[len(REQUEST_VERSION_TWO):]
 
94
        else:
 
95
            protocol_class = SmartServerRequestProtocolOne
 
96
        protocol = protocol_class(self.backing_transport, self._write_out)
 
97
        protocol.accept_bytes(bytes)
 
98
        return protocol
 
99
 
76
100
    def _serve_one_request(self, protocol):
77
101
        """Read one request from input, process, send back a response.
78
102
        
89
113
        """Called when an unhandled exception from the protocol occurs."""
90
114
        raise NotImplementedError(self.terminate_due_to_error)
91
115
 
 
116
    def _get_bytes(self, desired_count):
 
117
        """Get some bytes from the medium.
 
118
 
 
119
        :param desired_count: number of bytes we want to read.
 
120
        """
 
121
        raise NotImplementedError(self._get_bytes)
 
122
 
 
123
    def _get_line(self):
 
124
        """Read bytes from this request's response until a newline byte.
 
125
        
 
126
        This isn't particularly efficient, so should only be used when the
 
127
        expected size of the line is quite short.
 
128
 
 
129
        :returns: a string of bytes ending in a newline (byte 0x0A).
 
130
        """
 
131
        # XXX: this duplicates SmartClientRequestProtocolOne._recv_tuple
 
132
        line = ''
 
133
        while not line or line[-1] != '\n':
 
134
            new_char = self._get_bytes(1)
 
135
            line += new_char
 
136
            if new_char == '':
 
137
                # Ran out of bytes before receiving a complete line.
 
138
                break
 
139
        return line
 
140
 
92
141
 
93
142
class SmartServerSocketStreamMedium(SmartServerStreamMedium):
94
143
 
109
158
                protocol.accept_bytes(self.push_back)
110
159
                self.push_back = ''
111
160
            else:
112
 
                bytes = self.socket.recv(4096)
 
161
                bytes = self._get_bytes(4096)
113
162
                if bytes == '':
114
163
                    self.finished = True
115
164
                    return
116
165
                protocol.accept_bytes(bytes)
117
166
        
118
167
        self.push_back = protocol.excess_buffer
 
168
 
 
169
    def _get_bytes(self, desired_count):
 
170
        # We ignore the desired_count because on sockets it's more efficient to
 
171
        # read 4k at a time.
 
172
        return self.socket.recv(4096)
119
173
    
120
174
    def terminate_due_to_error(self):
121
175
        """Called when an unhandled exception from the protocol occurs."""
155
209
                # Finished serving this request.
156
210
                self._out.flush()
157
211
                return
158
 
            bytes = self._in.read(bytes_to_read)
 
212
            bytes = self._get_bytes(bytes_to_read)
159
213
            if bytes == '':
160
214
                # Connection has been closed.
161
215
                self.finished = True
163
217
                return
164
218
            protocol.accept_bytes(bytes)
165
219
 
 
220
    def _get_bytes(self, desired_count):
 
221
        return self._in.read(desired_count)
 
222
 
166
223
    def terminate_due_to_error(self):
167
224
        # TODO: This should log to a server log file, but no such thing
168
225
        # exists yet.  Andrew Bennetts 2006-09-29.
270
327
 
271
328
        This method will block and wait for count bytes to be read. It may not
272
329
        be invoked until finished_writing() has been called - this is to ensure
273
 
        a message-based approach to requests, for compatability with message
 
330
        a message-based approach to requests, for compatibility with message
274
331
        based mediums like HTTP.
275
332
        """
276
333
        if self._state == "writing":
288
345
        """
289
346
        raise NotImplementedError(self._read_bytes)
290
347
 
 
348
    def read_line(self):
 
349
        """Read bytes from this request's response until a newline byte.
 
350
        
 
351
        This isn't particularly efficient, so should only be used when the
 
352
        expected size of the line is quite short.
 
353
 
 
354
        :returns: a string of bytes ending in a newline (byte 0x0A).
 
355
        """
 
356
        # XXX: this duplicates SmartClientRequestProtocolOne._recv_tuple
 
357
        line = ''
 
358
        while not line or line[-1] != '\n':
 
359
            new_char = self.read_bytes(1)
 
360
            line += new_char
 
361
            if new_char == '':
 
362
                raise errors.SmartProtocolError(
 
363
                    'unexpected end of file reading from server')
 
364
        return line
 
365
 
291
366
 
292
367
class SmartClientMedium(object):
293
368
    """Smart client is a medium for sending smart protocol requests over."""
523
598
        """
524
599
        return self._medium._read_bytes(count)
525
600
 
526