DebugClients/Ruby/AsyncFile.rb

changeset 4553
a6b2acd1a355
parent 4552
b1ea4ea0190e
child 4554
f3428ddd577c
equal deleted inserted replaced
4552:b1ea4ea0190e 4553:a6b2acd1a355
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2015 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 =begin edoc
7 File implementing an asynchronous file like socket interface for the debugger.
8 =end
9
10 require 'socket'
11
12 require 'DebugProtocol'
13
14 def AsyncPendingWrite(file)
15 =begin edoc
16 Module function to check for data to be written.
17
18 @param file The file object to be checked (file)
19 @return Flag indicating if there is data wating (int)
20 =end
21 begin
22 pending = file.pendingWrite
23 rescue
24 pending = 0
25 end
26 return pending
27 end
28
29 class AsyncFile
30 =begin edoc
31 # Class wrapping a socket object with a file interface.
32 =end
33 @@maxtries = 10
34 @@maxbuffersize = 1024 * 1024 * 4
35
36 def initialize(sock, mode, name)
37 =begin edoc
38 Constructor
39
40 @param sock the socket object being wrapped
41 @param mode mode of this file (string)
42 @param name name of this file (string)
43 =end
44
45 # Initialise the attributes.
46 @closed = false
47 @sock = sock
48 @mode = mode
49 @name = name
50 @nWriteErrors = 0
51
52 @wpending = ''
53 end
54
55 def checkMode(mode)
56 =begin edoc
57 Private method to check the mode.
58
59 This method checks, if an operation is permitted according to
60 the mode of the file. If it is not, an IOError is raised.
61
62 @param mode the mode to be checked (string)
63 =end
64 if mode != @mode
65 raise IOError, '[Errno 9] Bad file descriptor'
66 end
67 end
68
69 def nWrite(n)
70 =begin edoc
71 Private method to write a specific number of pending bytes.
72
73 @param n the number of bytes to be written (int)
74 =end
75 if n > 0
76 begin
77 buf = "%s%s" % [@wpending[0...n], EOT]
78 sent = @sock.send(buf, 0)
79 if sent > n
80 sent -= EOT.length
81 end
82 @wpending = @wpending[sent..-1]
83 @nWriteErrors = 0
84 rescue IOError
85 @nWriteErrors += 1
86 if @nWriteErrors > self.maxtries
87 raise
88 # assume that an error that occurs 10 times wont go away
89 end
90 end
91 end
92 end
93
94 def pendingWrite
95 =begin edoc
96 Public method that returns the number of bytes waiting to be written.
97
98 @return the number of bytes to be written (int)
99 =end
100 ind = @wpending.rindex("\n")
101 if ind
102 return ind + 1
103 else
104 return 0
105 end
106 end
107
108 def close
109 =begin edoc
110 Public method to close the file.
111 =end
112 if not @closed
113 flush()
114 begin
115 @sock.close()
116 rescue IOError
117 end
118 @closed = true
119 end
120 end
121
122 def flush
123 =begin edoc
124 Public method to write all pending bytes.
125 =end
126 nWrite(@wpending.length)
127 end
128
129 def isatty
130 =begin edoc
131 Public method to indicate whether a tty interface is supported.
132
133 @return always false
134 =end
135 return false
136 end
137
138 def fileno
139 =begin edoc
140 Public method returning the file number.
141
142 @return file number (int)
143 =end
144 return @sock.fileno()
145 end
146
147 def getSock
148 =begin edoc
149 Public method to get the socket object.
150
151 @return the socket object
152 =end
153 return @sock
154 end
155
156 def read(size = -1)
157 =begin edoc
158 Public method to read bytes from this file.
159
160 @param size maximum number of bytes to be read (int)
161 @return the bytes read (any)
162 =end
163 checkMode('r')
164
165 if size < 0
166 size = 20000
167 end
168
169 return @sock.recv(size)
170 end
171
172 def readline(size = -1)
173 =begin edoc
174 Public method to read a line from this file.
175
176 <b>Note</b>: This method will not block and may return
177 only a part of a line if that is all that is available.
178
179 @param size maximum number of bytes to be read (int)
180 @return one line of text up to size bytes (string)
181 =end
182 checkMode('r')
183
184 if size < 0
185 size = 20000
186 end
187
188 # The integration of the debugger client event loop and the connection
189 # to the debugger relies on the two lines of the debugger command being
190 # delivered as two separate events. Therefore we make sure we only
191 # read a line at a time.
192 line = @sock.recv(size, Socket::MSG_PEEK)
193
194 eol = line.index("\n")
195
196 if eol and eol >= 0
197 size = eol + 1
198 else
199 size = line.length
200 end
201
202 # Now we know how big the line is, read it for real.
203 return @sock.recv(size)
204 end
205
206 def readlines(sizehint = -1)
207 =begin edoc
208 Public method to read all lines from this file.
209
210 @param sizehint hint of the numbers of bytes to be read (int)
211 @return list of lines read (list of strings)
212 =end
213 lines = []
214 room = sizehint
215
216 line = readline(room)
217 linelen = line.length
218
219 while linelen > 0
220 lines << line
221
222 if sizehint >= 0
223 room = room - linelen
224
225 if room <= 0
226 break
227 end
228 end
229
230 line = readline(room)
231 linelen = line.length
232 end
233
234 return lines
235 end
236
237 def gets()
238 =begin edoc
239 Public method to read a line from this file.
240 =end
241 readline()
242 end
243
244 def seek(offset, whence=IO::SEEK_SET)
245 =begin edoc
246 Public method to move the filepointer.
247
248 @exception IOError This method is not supported and always raises an
249 IOError.
250 =end
251 raise IOError, '[Errno 29] Illegal seek'
252 end
253
254 def tell
255 =begin edoc
256 Public method to get the filepointer position.
257
258 @exception IOError This method is not supported and always raises an
259 IOError.
260 =end
261 raise IOError, '[Errno 29] Illegal seek'
262 end
263
264 def <<(s)
265 =begin edoc
266 Synonym for write(s).
267
268 @param s bytes to be written (string)
269 =end
270 write(s)
271 end
272
273 def write(s)
274 =begin edoc
275 Public method to write a string to the file.
276
277 @param s bytes to be written (string)
278 =end
279 checkMode("w")
280 tries = 0
281 s = s.to_s
282 if @wpending.length == 0
283 @wpending = s.dup
284 elsif @wpending.length + s.length > @@maxbuffersize
285 # flush wpending if too big
286 while @wpending.length > 0
287 # if we have a persistent error in sending the data, an
288 # exception will be raised in nWrite
289 flush
290 tries += 1
291 if tries > @@maxtries
292 raise IOError, "Too many attempts to send data"
293 end
294 end
295 @wpending = s.dup
296 else
297 @wpending << s
298 end
299 nWrite(pendingWrite())
300 end
301
302 def writelines(list)
303 =begin edoc
304 Public method to write a list of strings to the file.
305
306 @param list the list to be written (list of string)
307 =end
308 list.each do |s|
309 write(s)
310 end
311 end
312 end

eric ide

mercurial