# Twisted stackless example
# See the `blocking' echo server at the end
#
# agl@imperialviolet.org

from stackless import channel, tasklet
import stackless
from twisted.internet import reactor, protocol
import twisted.python
import twisted.python.rebuild

def twisted_tasklet ():
	reactor.run ()

tasklet (twisted_tasklet) ()

class StacklessProtocol (protocol.Protocol):
	def __init__ (self, in_buf_size = 32768, out_buf_size = 32768):
		self.__chan = channel ()
		self.__task = tasklet (self.process)()
		self.__out_buf = ""
		self.__in_buf  = ""
		self.__n = 0
		self.__waiting_on_read   = False
		self.__waiting_on_write  = False
		self.__waiting_for_write = True
		self.__in_buf_size  = in_buf_size
		self.__out_buf_size = out_buf_size
		self.__task.run ()
	def reada (self, n):
		while len (self.__in_buf) < n:
			self.__waiting_on_read = 1
			self.__chan.receive ()
		a = self.__in_buf[:n]
		self.__in_buf = self.__in_buf[n:]

		return a
	def read (self):
		while len (self.__in_buf) == 0:
			self.__waiting_on_read = 1
			self.__chan.receive ()
		a = self.__in_buf
		self.__in_buf = ""

		return a
	def write (self, s):
		while len (self.__out_buf) > self.__out_buf_size:
			self.__waiting_on_write = 1
			self.__chan.receive ()
		self.__out_buf += s
		if self.__waiting_for_write:
			reactor.callLater (0, self.__write_ready)
			self__waiting_for_write = False
	
	def resumeProducing (self):
		if len (self.__out_buf) == 0:
			self.transport.unregisterProducer ()
			self.__waiting_for_write = True
		else:
			self.transport.write (self.__out_buf)
			self.__out_buf = ""
			if self.__waiting_on_write:
				self.__waiting_on_write = False
				self.__chan.send (1)
	
	def __write_ready (self):
		self.transport.registerProducer (self, 0)
	
	def dataReceived(self, data):
		self.__in_buf += data
		if len (self.__in_buf) > self.__in_buf_size:
			self.transport.pauseProducing ()
		if self.__waiting_on_read:
			self.__waiting_on_read = False
			self.__chan.send (1)

class LineReader (object):
	def line_read (self):
		while True:
			line = self.__line_get ()
			if line != None:
				return line

			try:
				self.__linebuf += self.read ()
			except AttributeError:
				self.__linebuf = ""
				self.__linebuf += self.read ()
	def __line_get (self):
		try:
			index = self.__linebuf.find ('\n')
		except AttributeError:
			self.__linebuf = ""
			return None
		if index == -1:
			return None
		a = self.__linebuf[:index]
		self.__linebuf = self.__linebuf[index+1:]

		if len (a) > 0 and a[-1] == '\r':
			a = a[:-1]

		return a

class MyServer(StacklessProtocol, LineReader):
	def process (self):
		while True:
			self.write (self.line_read () + '\n')

factory = protocol.Factory ()
factory.protocol = MyServer

reactor.listenTCP (8007, factory)

stackless.run ()

