Commits

Anonymous committed fa8b718 Draft

Client support and free loops for standalone programs.

Comments (0)

Files changed (7)

concussion/__init__.py

 import logmod
 log = logmod.log
 from timers import call_later, call_every
-from core import until, until_eol, bytes, sleep, Connection, ConnectionClosed
-from app import Application, Service
+from core import until, until_eol, bytes, sleep, Connection, ConnectionClosed, Loop
+from app import Application, Service 
+from client import Client, call, response

concussion/app.py

 		self.logger = logger
 		self.add_log = self.logger.add_log
 		self._services = []
+		self._loops = []
 
 	def run(self):
 		self._run = True
 			s.bind_and_listen()
 			event.event(s.accept_new_connection,
 			handle=s.sock, evtype=event.EV_READ | event.EV_PERSIST, arg=s).add()
+		for l in self._loops:
+			l.iterate()
 
 		def checkpoint():
 			if not self._run:
 	def add_service(self, service):
 		service.application = self
 		self._services.append(service)
+
+	def add_loop(self, loop):
+		loop.application = self
+		self._loops.append(loop)
 		
 	def halt(self):	
 		self._run = False

concussion/client.py

+import socket
+from collections import deque
+
+class call(object):
+	def __init__(self, f, inst=None):
+		self.f = f
+		self.client = inst
+
+	def __call__(self, *args, **kw):
+		self.gen = self.f(self.client, *args, **kw)
+		return self
+
+	def __get__(self, inst, cls):
+		return call(self.f, inst)
+
+	def go(self, callback): # XXX errback-type stuff?
+		self.client.conn.callbacks.append(callback)
+		self.client.jobs.append(self.gen)
+		self.client.conn.wake()
+
+class response(object):
+	def __init__(self, value):
+		self.value = value
+
+class Client(object):
+	def __init__(self, connection_handler=None):
+		self.connection_handler = connection_handler or self.client_conn_handler
+		self.jobs = deque()
+	 
+	def connect(self, addr, port):  
+		remote_addr = (addr, port)
+		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+		sock.connect(remote_addr)
+		from concussion.core import Connection
+		self.conn = Connection(sock, (addr, port), self.client_conn_handler)
+		self.conn.iterate()
+
+	def client_conn_handler(self, addr):
+		from concussion.core import sleep
+		yield self.on_connect()
+
+		while True:
+			if not self.jobs:
+				yield sleep()
+			if not self.jobs:
+				continue
+			mygen = self.jobs.popleft()
+			yield mygen
+
+	def on_connect(self):
+		if 0: yield 0

concussion/core.py

 import socket
 import event
 from types import GeneratorType
+from collections import deque
 
 from concussion import pipeline
 from concussion import buffer
 from concussion import call_later
+from concussion.client import call, response
 
 class ConnectionClosed(socket.error): pass
 
 		self.sentinel = sentinel
 
 class sleep(object):
-	def __init__(self, duration):
+	def __init__(self, duration=0):
 		self.duration = duration
 	
 class Connection(object):
 		self.pipeline = pipeline.Pipeline()
 		self.buffer = buffer.Buffer()
 		self._rev = event.event(self.handle_read, handle=sock, evtype=event.EV_READ | event.EV_PERSIST, arg=None)
+		self._rev.add()
 		self._wev = None
 		self.g = self.cycle_all(connection_handler(addr))
+		self.callbacks = deque()
 
 	def cycle_all(self, current):
 		'''Effectively flattens all iterators.
 		'''
-		self._rev.add()
 		last = None
 		stack = []
 		while True:
 				self.pipeline.close_request()
 				break
 			n_val = None
-			if isinstance(ret, basestring) or hasattr(ret, 'seek'):
+			if isinstance(ret, response):
+				c = self.callbacks.popleft()
+				c(ret.value)
+				break
+			elif isinstance(ret, call):
+				ret.go(self.iterate)
+				break
+			elif isinstance(ret, basestring) or hasattr(ret, 'seek'):
 				self.pipeline.add(ret)
 			elif type(ret) is until or type(ret) is bytes:
 				self.buffer.set_term(ret.sentinel)
 				if n_val == None:
 					break
 			elif type(ret) is sleep:
-				call_later(ret.duration, self.wake)
+				if ret.duration:
+					call_later(ret.duration, self.wake)
 				break
 
 		if not self.pipeline.empty:
 			self.set_writable(True)
+
+class Loop(Connection):
+	'''A way to write a connection-less loop.
+
+	XXX
+	This is probably upside down right now.  Fix it eventually.
+	'''
+	def __init__(self, loop_callable):
+		self.g = self.cycle_all(loop_callable())
+		self.pipeline = pipeline.Pipeline()

examples/client.py

+'''Echo test.
+'''
+
+from concussion import Application, Client, call, Loop, sleep, until_eol, response
+
+class EchoClient(Client):
+	@call
+	def echo(self, message):
+		yield "%s!\r\n" % message
+		back = yield until_eol()
+		yield response(back)
+
+
+def echo_loop(n):
+	def _loop():
+		client = EchoClient()
+		client.connect('localhost', 8013)
+		while 1:
+			bar = yield client.echo("foo %s" % n)
+			print "%s: remote service said %r" % (n, bar)
+			yield sleep(2)
+	return _loop
+
+a = Application()
+
+for x in xrange(500):
+	a.add_loop(Loop(echo_loop(x)))
+a.run()
 from concussion import Application, Service, until_eol
 
 def hi_server(addr):
-	yield "hi"
-	inp = (yield until_eol())
-	yield "you said %s" % inp
+	while 1:
+		yield "hi"
+		inp = (yield until_eol())
+		yield "you said %s" % inp
 
 app = Application()
 app.add_service(Service(hi_server, 8013))
 from concussion import Application, Service
 from concussion.protocols import http
 
+content = "H" * 1247
+
 def hello_http(req):
-	content = "Hello, Worldz!"
 	headers = http.HttpHeaders()
 	headers.add('Content-Length', len(content))
 	headers.add('Content-Type', 'text/plain')
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.