10039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# -*- Mode: Python; tab-width: 4 -*- 2658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters# Id: asynchat.py,v 2.26 2000/09/07 22:29:26 rushing Exp 3146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters# Author: Sam Rushing <rushing@nightmare.com> 40039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 50039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# ====================================================================== 60039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# Copyright 1996 by Sam Rushing 7146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters# 80039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# All Rights Reserved 9146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters# 100039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# Permission to use, copy, modify, and distribute this software and 110039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# its documentation for any purpose and without fee is hereby 120039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# granted, provided that the above copyright notice appear in all 130039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# copies and that both that copyright notice and this permission 140039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# notice appear in supporting documentation, and that the name of Sam 150039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# Rushing not be used in advertising or publicity pertaining to 160039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# distribution of the software without specific, written prior 170039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# permission. 18146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters# 190039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 200039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 210039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR 220039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 230039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 240039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 250039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 260039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# ====================================================================== 270039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 28e4a1b6d7c4e96dd2af0541dd12444932260e2a66Guido van Rossumr"""A class supporting chat-style (command/response) protocols. 294b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum 304b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van RossumThis class adds support for 'chat' style protocols - where one side 314b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumsends a 'command', and the other sends a response (examples would be 324b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumthe common internet protocols - smtp, nntp, ftp, etc..). 334b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum 344b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van RossumThe handle_read() method looks at the input stream for the current 354b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n' 364b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumfor multi-line output), calling self.found_terminator() on its 374b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumreceipt. 384b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum 394b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumfor example: 404b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van RossumSay you build an async nntp client using this class. At the start 414b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumof the connection, you'll have self.terminator set to '\r\n', in 424b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumorder to process the single-line greeting. Just before issuing a 434b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum'LIST' command you'll set it to '\r\n.\r\n'. The output of the LIST 444b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumcommand will be accumulated (using your own 'collect_incoming_data' 454b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossummethod) up to the terminator, and then control will be returned to 464b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossumyou - by calling your self.found_terminator() method. 474b8c6eaf8b287a27e0054cf6c751448b2077e83bGuido van Rossum""" 480039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossumimport asyncore 49ac093c6af04237deceedaab55d299819cbede7f9Raymond Hettingerfrom collections import deque 500039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 51d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 52fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinnerclass async_chat(asyncore.dispatcher): 53146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters """This is an abstract class. You must derive from this class, and add 54146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters the two methods collect_incoming_data() and found_terminator()""" 55146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 56146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # these are overridable defaults 57146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 58fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner ac_in_buffer_size = 65536 59fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner ac_out_buffer_size = 65536 60146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 61d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # we don't want to enable the use of encoding by default, because that is a 62d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # sign of an application bug that we don't want to pass silently 63d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 64fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner use_encoding = 0 65fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner encoding = 'latin-1' 66d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 67fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def __init__(self, sock=None, map=None): 68d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # for string terminator matching 69076da0957b1af50cccf40ec5c60742212b4a1f90Guido van Rossum self.ac_in_buffer = b'' 70d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 7150254c57cd7a562441b7ff385d59c0255301f3ffSerhiy Storchaka # we use a list here rather than io.BytesIO for a few reasons... 7250254c57cd7a562441b7ff385d59c0255301f3ffSerhiy Storchaka # del lst[:] is faster than bio.truncate(0) 7350254c57cd7a562441b7ff385d59c0255301f3ffSerhiy Storchaka # lst = [] is faster than bio.truncate(0) 74d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.incoming = [] 75d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 76d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # we toss the use of the "simple producer" and replace it with 77d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # a pure deque, which the original fifo was a wrapping of 78d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo = deque() 79fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner asyncore.dispatcher.__init__(self, sock, map) 80146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 817dd5f3cf698a7ffb7e532719639c85f81a65dbe8Andrew M. Kuchling def collect_incoming_data(self, data): 82ce36ad8a467d914eb5c91f33835b9eaea18ee93bCollin Winter raise NotImplementedError("must be implemented in subclass") 83863ac44b74cd66f7d289748816d65c65808c149bTim Peters 84d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson def _collect_incoming_data(self, data): 85d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.incoming.append(data) 86d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 87d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson def _get_data(self): 88d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson d = b''.join(self.incoming) 89d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson del self.incoming[:] 90d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson return d 91d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 927dd5f3cf698a7ffb7e532719639c85f81a65dbe8Andrew M. Kuchling def found_terminator(self): 93ce36ad8a467d914eb5c91f33835b9eaea18ee93bCollin Winter raise NotImplementedError("must be implemented in subclass") 94863ac44b74cd66f7d289748816d65c65808c149bTim Peters 95fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def set_terminator(self, term): 96fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner """Set the input delimiter. 97fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner 98fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner Can be a fixed string of any length, an integer, or None. 99fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner """ 100d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if isinstance(term, str) and self.use_encoding: 101d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson term = bytes(term, self.encoding) 102630a4f63c539345a6432d6177931b5fcc2f18aa7Victor Stinner elif isinstance(term, int) and term < 0: 103630a4f63c539345a6432d6177931b5fcc2f18aa7Victor Stinner raise ValueError('the number of received bytes must be positive') 104146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.terminator = term 105146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 106fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def get_terminator(self): 107146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return self.terminator 108146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 109146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # grab some more data from the socket, 110146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # throw it to the collector method, 111146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # check for the terminator, 112146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # if found, transition to the next state. 113146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 114fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def handle_read(self): 115146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 116146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters try: 117fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner data = self.recv(self.ac_in_buffer_size) 11845cff66cf63593695ff5324d3765d8a1a1125adfVictor Stinner except BlockingIOError: 11945cff66cf63593695ff5324d3765d8a1a1125adfVictor Stinner return 1200832af6628ca5ac02d0226899725297dd508470bAndrew Svetlov except OSError as why: 121146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.handle_error() 122146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return 123146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 124d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if isinstance(data, str) and self.use_encoding: 125d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson data = bytes(str, self.encoding) 126d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.ac_in_buffer = self.ac_in_buffer + data 127146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 128146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # Continue to search for self.terminator in self.ac_in_buffer, 129146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # while calling self.collect_incoming_data. The while loop 130146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # is necessary because we might read several data+terminator 131d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # combos with a single recv(4096). 132146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 133146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters while self.ac_in_buffer: 134146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters lb = len(self.ac_in_buffer) 135146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters terminator = self.get_terminator() 136ca69f0248c94a08f2077f8e17cf6ad556a2d9d16Andrew M. Kuchling if not terminator: 137146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # no terminator, collect it all 138fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer) 139806c2469cb2e16c6cfd73de9a216933bd55c131fGuido van Rossum self.ac_in_buffer = b'' 140d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson elif isinstance(terminator, int): 141146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # numeric terminator 142146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters n = terminator 143146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if lb < n: 144fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer) 145076da0957b1af50cccf40ec5c60742212b4a1f90Guido van Rossum self.ac_in_buffer = b'' 146146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.terminator = self.terminator - lb 147146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 148fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer[:n]) 149146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.ac_in_buffer = self.ac_in_buffer[n:] 150146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.terminator = 0 151146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.found_terminator() 152146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 153146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # 3 cases: 154146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # 1) end of buffer matches terminator exactly: 155146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # collect data, transition 156146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # 2) end of buffer matches some prefix: 157146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # collect data to the prefix 158146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # 3) end of buffer does not match any prefix: 159146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # collect data 160146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters terminator_len = len(terminator) 161b5d1392d9236eae981796cb7ae15d8ecd5035ac6Tim Peters index = self.ac_in_buffer.find(terminator) 162146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if index != -1: 163146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # we found the terminator 164146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if index > 0: 165fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner # don't bother reporting the empty string 166fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner # (source of subtle bugs) 167fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer[:index]) 168146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.ac_in_buffer = self.ac_in_buffer[index+terminator_len:] 169fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner # This does the Right Thing if the terminator 170fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner # is changed here. 171146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.found_terminator() 172146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 173146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # check for a prefix of the terminator 174fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner index = find_prefix_at_end(self.ac_in_buffer, terminator) 175146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if index: 176146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if index != lb: 177146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # we found a prefix, collect up to the prefix 178fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer[:-index]) 179146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.ac_in_buffer = self.ac_in_buffer[-index:] 180146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters break 181146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 182146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # no prefix, collect it all 183fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner self.collect_incoming_data(self.ac_in_buffer) 184076da0957b1af50cccf40ec5c60742212b4a1f90Guido van Rossum self.ac_in_buffer = b'' 185146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 186fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def handle_write(self): 187d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.initiate_send() 188146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 189fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def handle_close(self): 190146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.close() 191146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 192fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def push(self, data): 193d9e810a8701b92371232eece5896a799c33de505Victor Stinner if not isinstance(data, (bytes, bytearray, memoryview)): 194d9e810a8701b92371232eece5896a799c33de505Victor Stinner raise TypeError('data argument must be byte-ish (%r)', 195d9e810a8701b92371232eece5896a799c33de505Victor Stinner type(data)) 196d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson sabs = self.ac_out_buffer_size 197d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if len(data) > sabs: 198d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson for i in range(0, len(data), sabs): 199d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.append(data[i:i+sabs]) 200d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson else: 201d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.append(data) 202146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.initiate_send() 203146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 204fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def push_with_producer(self, producer): 205d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.append(producer) 206146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.initiate_send() 207146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 208fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def readable(self): 209146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters "predicate for inclusion in the readable for select()" 210d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # cannot use the old predicate, it violates the claim of the 211d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # set_terminator method. 212d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 213d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # return (len(self.ac_in_buffer) <= self.ac_in_buffer_size) 214d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson return 1 215146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 216fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def writable(self): 217146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters "predicate for inclusion in the writable for select()" 218d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson return self.producer_fifo or (not self.connected) 219146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 220fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def close_when_done(self): 221146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters "automatically close this channel once the outgoing queue is empty" 222d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.append(None) 223d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 224d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson def initiate_send(self): 225d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson while self.producer_fifo and self.connected: 226d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson first = self.producer_fifo[0] 227d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # handle empty string/buffer or None entry 228d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if not first: 229d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson del self.producer_fifo[0] 230d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if first is None: 231d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.handle_close() 232146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return 233d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 234d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # handle classic producer behavior 235d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson obs = self.ac_out_buffer_size 236d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson try: 237d9f38bc7043c6d94ea7d76249d48d18322b46e92Giampaolo Rodola' data = first[:obs] 238d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson except TypeError: 239d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson data = first.more() 240146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters if data: 241d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.appendleft(data) 242146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 243d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson del self.producer_fifo[0] 244d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson continue 245146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 246d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if isinstance(data, str) and self.use_encoding: 247d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson data = bytes(data, self.encoding) 248146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 249d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # send the data 250146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters try: 251d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson num_sent = self.send(data) 2520832af6628ca5ac02d0226899725297dd508470bAndrew Svetlov except OSError: 253146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.handle_error() 254146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return 255146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters 256d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if num_sent: 257d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson if num_sent < len(data) or obs < len(first): 258d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo[0] = first[num_sent:] 259d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson else: 260d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson del self.producer_fifo[0] 261d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson # we tried to send some actual data 262d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson return 263d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson 264fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def discard_buffers(self): 265146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters # Emergencies only! 266076da0957b1af50cccf40ec5c60742212b4a1f90Guido van Rossum self.ac_in_buffer = b'' 267d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson del self.incoming[:] 268d74900ebb5a22b387b49684990da1925e1d6bdc9Josiah Carlson self.producer_fifo.clear() 269da85a272a6216cf3583db8e25155cb3a7168b081Andrew M. Kuchling 270fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner 2710039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossumclass simple_producer: 272a8d0f4fd2d10a1f5e05d31e048e52a1192d84321Guido van Rossum 273fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def __init__(self, data, buffer_size=512): 274146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.data = data 275146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.buffer_size = buffer_size 2760039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 277fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner def more(self): 278fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner if len(self.data) > self.buffer_size: 279146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters result = self.data[:self.buffer_size] 280146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters self.data = self.data[self.buffer_size:] 281146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return result 282146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters else: 283146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters result = self.data 284076da0957b1af50cccf40ec5c60742212b4a1f90Guido van Rossum self.data = b'' 285146965abf2378cdb248cead43a613fb81aa7d1a4Tim Peters return result 2860039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 287fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner 2880039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# Given 'haystack', see if any prefix of 'needle' is at its end. This 2890039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# assumes an exact match has already been checked. Return the number of 2900039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# characters matched. 2910039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# for example: 292fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner# f_p_a_e("qwerty\r", "\r\n") => 1 293fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner# f_p_a_e("qwertydkjf", "\r\n") => 0 294fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinner# f_p_a_e("qwerty\r\n", "\r\n") => <undefined> 2950039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 2960039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum# this could maybe be made faster with a computed regex? 297d305f515f9c4e3cedb3e47ec2711f1dd2a99ceb5Andrew M. Kuchling# [answer: no; circa Python-2.0, Jan 2001] 298c63a396c5fc55beeaf3c973f137e160fc844d5a6Andrew M. Kuchling# new python: 28961/s 299c63a396c5fc55beeaf3c973f137e160fc844d5a6Andrew M. Kuchling# old python: 18307/s 300d305f515f9c4e3cedb3e47ec2711f1dd2a99ceb5Andrew M. Kuchling# re: 12820/s 301d305f515f9c4e3cedb3e47ec2711f1dd2a99ceb5Andrew M. Kuchling# regex: 14035/s 3020039d7b4e6f07411f788dbcb52cd05d26fc7fec5Guido van Rossum 303fd5d1b51d64280d938b7cdc9d78c632b21b45dffVictor Stinnerdef find_prefix_at_end(haystack, needle): 304863ac44b74cd66f7d289748816d65c65808c149bTim Peters l = len(needle) - 1 305863ac44b74cd66f7d289748816d65c65808c149bTim Peters while l and not haystack.endswith(needle[:l]): 306863ac44b74cd66f7d289748816d65c65808c149bTim Peters l -= 1 307863ac44b74cd66f7d289748816d65c65808c149bTim Peters return l 308