<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Learning about IPushProducer</TITLE>
<META http-equiv=Content-Type content="text/html; charset=us-ascii">
<META content="MSHTML 6.00.2900.3059" name=GENERATOR></HEAD>
<BODY>
<DIV dir=ltr align=left><FONT face=Arial color=#0000ff size=2><SPAN 
class=035294315-16032007>BTW, how was it that my pauseProducing ever got invoked 
below?&nbsp; after all I registered&nbsp;my producer&nbsp;(erroneously, no doubt 
since it implements IPushProducer) as a pull producer by using the 2nd argument 
of 'False' below:</SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT face=Arial color=#0000ff size=2><SPAN 
class=035294315-16032007></SPAN></FONT>&nbsp;</DIV>
<DIV dir=ltr align=left><FONT face=Arial size=2><SPAN 
class=035294315-16032007><FONT 
face="Courier New">self.consumer.registerProducer(self, False)</FONT><FONT 
face="Times New Roman" size=3> </FONT></SPAN></FONT></DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial><FONT color=#0000ff><FONT size=2><SPAN 
class=035294315-16032007>If indeed it's registered as a pull producer I wouldn't 
think its pause&nbsp;should ever be called. Does&nbsp;twisted actually use the 
type of the class to see what to call?&nbsp; Or getattr(class,'pauseProducing') 
or somesuch?&nbsp; &nbsp;If so, what's the purpose of 'True' or 'False' during 
registration?</SPAN></FONT></FONT></FONT></DIV>
<DIV><FONT face=Arial><FONT color=#0000ff><FONT size=2><SPAN 
class=035294315-16032007></SPAN></FONT></FONT></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial><FONT color=#0000ff><FONT size=2><SPAN 
class=035294315-16032007>from the docs:</SPAN></FONT></FONT></FONT></DIV>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
  <DIV><FONT face=Arial><FONT><FONT size=2><SPAN class=035294315-16032007>
  <H3><FONT color=#0000ff>registerProducer(producer, streaming)</FONT><A 
  name=auto8></A></H3>
  <P><FONT color=#0000ff>So that a consumer can invoke methods on a producer, 
  the consumer needs to be told about the producer. This is done with the <CODE 
  class=python>registerProducer</CODE> method. The first argument is either a 
  <CODE class=python>IPullProducer</CODE> or <CODE 
  class=python>IPushProducer</CODE> provider; the second argument indicates 
  which of these interfaces is provided: <CODE class=python>True</CODE> for push 
  producers, <CODE class=python>False</CODE> for pull 
producers.</FONT></P></DIV></BLOCKQUOTE>
<P dir=ltr><SPAN class=035294315-16032007><FONT 
color=#0000ff>Thanks!</FONT></SPAN></SPAN></FONT></FONT></FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
  <DIV class=OutlookMessageHeader lang=en-us dir=ltr align=left>
  <HR tabIndex=-1>
  </DIV>
  <DIV class=OutlookMessageHeader lang=en-us dir=ltr align=left><FONT 
  face=Tahoma size=2><B>From:</B> twisted-python-bounces@twistedmatrix.com 
  [mailto:twisted-python-bounces@twistedmatrix.com] <B>On Behalf Of </B>Rutt, 
  Benjamin<BR><B>Sent:</B> Tuesday, March 06, 2007 12:04 PM<BR><B>To:</B> 
  twisted-python@twistedmatrix.com<BR><B>Subject:</B> [Twisted-Python] Learning 
  about IPushProducer<BR></FONT><BR></DIV>
  <DIV></DIV><!-- Converted from text/rtf format -->
  <P><FONT face="Courier New" size=2>When running the following code (my 2nd 
  twisted program!), it works as I had hoped - it doesn't starve any clients 
  that want to receive data back, even with a simultaneously active really long 
  streaming server-to-client communication (i.e. one piggy client asking for 
  millions of bytes).&nbsp; i.e. another client can get in and ask for just a 
  few bytes while a large payload is being delivered to a different 
  client.&nbsp; Which is great!</FONT></P>
  <P><FONT face="Courier New" size=2>Here's a sample interaction from the client 
  side:</FONT> </P>
  <P><FONT face="Courier New" size=2>$ telnet localhost 8007</FONT> <BR><FONT 
  face="Courier New" size=2>Trying 127.0.0.1...</FONT> <BR><FONT 
  face="Courier New" size=2>Connected to localhost.</FONT> <BR><FONT 
  face="Courier New" size=2>Escape character is '^]'.</FONT> <BR><FONT 
  face="Courier New" size=2>1</FONT> <BR><FONT face="Courier New" 
  size=2>x</FONT> <BR><FONT face="Courier New" size=2>2</FONT> <BR><FONT 
  face="Courier New" size=2>xx</FONT> <BR><FONT face="Courier New" 
  size=2>3</FONT> <BR><FONT face="Courier New" size=2>xxx</FONT> <BR><FONT 
  face="Courier New" size=2>10</FONT> <BR><FONT face="Courier New" 
  size=2>xxxxxxxxxx</FONT> <BR><FONT face="Courier New" size=2>99999</FONT> 
  <BR><FONT face="Courier New" 
  size=2>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</FONT></P>
  <P><FONT face="Courier New" size=2>[...lots of x's...]</FONT> <BR><FONT 
  face="Courier New" size=2>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</FONT> <BR><FONT 
  face="Courier New" size=2>bye</FONT> <BR><FONT face="Courier New" 
  size=2>Connection closed by foreign host.</FONT> <BR><FONT face="Courier New" 
  size=2>$ </FONT></P>
  <P><FONT face="Courier New" size=2>So I have 2 questions on my code:</FONT> 
  </P>
  <P><FONT face="Courier New" size=2>1) am I doing anything wrong in setting up 
  the plumbing?</FONT> <BR><FONT face="Courier New" size=2>2) does 
  pauseProducing() get called by another thread whilst resumeProducing() is 
  running?&nbsp; (I believe it must, otherwise my resumeProducing() would only 
  be entered once).&nbsp; If so I should have an appropriate mutex around the 
  read/write of self.pause, no?</FONT></P>
  <P><FONT face="Courier New" size=2>Here is the code, and output from the 
  server is at the end.&nbsp; Thanks -- Benjamin</FONT> </P>
  <P><FONT face="Courier New" size=2>#!/usr/bin/env python</FONT> <BR><FONT 
  face="Courier New" size=2>import os, os.path, sys, re, commands, pickle, 
  tempfile, getopt, datetime</FONT> <BR><FONT face="Courier New" size=2>import 
  socket, string, random, time, traceback, shutil, popen2</FONT> </P>
  <P><FONT face="Courier New" size=2>from zope.interface import 
  implements</FONT> <BR><FONT face="Courier New" size=2>from twisted.internet 
  import protocol, defer, interfaces, error, reactor</FONT> <BR><FONT 
  face="Courier New" size=2>from twisted.internet.protocol import Protocol, 
  Factory</FONT> <BR><FONT face="Courier New" size=2>from 
  twisted.protocols.basic import LineReceiver</FONT> </P>
  <P><FONT face="Courier New" size=2>class NonStarvingXGiver:</FONT> <BR><FONT 
  face="Courier New" size=2>&nbsp;&nbsp;&nbsp; 
  implements(interfaces.IPushProducer)</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp; def __init__(self, howmany, consumer):</FONT> 
  <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.howmany = howmany</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sent_already = 0</FONT> 
  <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.paused = False</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.consumer = 
  consumer</FONT> <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp; def 
  beginSendingXs(self):</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.deferred = deferred = 
  defer.Deferred()</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.consumer.registerProducer(self, False)</FONT> <BR><FONT 
  face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 
  deferred</FONT> <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp; def 
  pauseProducing(self):</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'pauseProducing: 
  invoked'</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.paused = True</FONT> 
  <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp; def 
  resumeProducing(self):</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'resumeProducing: 
  invoked'</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.paused = False</FONT> 
  <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  maxchunksz = 1024</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while not self.paused and 
  self.howmany &gt; self.sent_already:</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  chunksz = min(maxchunksz, self.howmany - self.sent_already)</FONT> <BR><FONT 
  face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.consumer.write('x' * chunksz)</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.sent_already += chunksz</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.howmany == 
  self.sent_already:</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.consumer.write('\n')</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.consumer.unregisterProducer()</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  print 'resumeProducing: exiting for the last time'</FONT> <BR><FONT 
  face="Courier New" size=2>&nbsp;&nbsp;&nbsp; def stopProducing(self):</FONT> 
  <BR><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  print 'stopProducing: invoked'</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.consumer.unregisterProducer()</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><BR><FONT 
  face="Courier New" size=2>class xgiver(LineReceiver):</FONT> <BR><FONT 
  face="Courier New" size=2>&nbsp;&nbsp;&nbsp; def lineReceived(self, 
  howmany):</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'got line [%s] from 
  client [%s]' % (howmany,</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.transport.getPeer())</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if howmany == 'bye':</FONT> 
  <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  print 'goodbye to', self.transport.getPeer()</FONT> <BR><FONT 
  face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.transport.loseConnection()</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  return</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:</FONT> <BR><FONT 
  face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  howmany = int(howmany)</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = 
  NonStarvingXGiver(howmany, self.transport)</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  s.beginSendingXs()</FONT> <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except Exception, ex:</FONT> 
  <BR><FONT face="Courier New" 
  size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  self.transport.write("invalid input " + howmany + "\n")</FONT> </P>
  <P><FONT face="Courier New" size=2># Next lines are magic:</FONT> <BR><FONT 
  face="Courier New" size=2>factory = Factory()</FONT> <BR><FONT 
  face="Courier New" size=2>factory.protocol = xgiver</FONT> </P>
  <P><FONT face="Courier New" size=2># 8007 is the port you want to run under. 
  Choose something &gt;1024</FONT> <BR><FONT face="Courier New" 
  size=2>reactor.listenTCP(8007, factory)</FONT> <BR><FONT face="Courier New" 
  size=2>reactor.run()</FONT> </P><BR>
  <P><FONT face="Courier New" 
  size=2>-------------------------------------------------------------------</FONT> 
  <BR><FONT face="Courier New" size=2>Server output:</FONT> </P>
  <P><FONT face="Courier New" size=2>$ ./xgiver.py </FONT><BR><FONT 
  face="Courier New" size=2>got line [1] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: exiting for the last time</FONT> <BR><FONT 
  face="Courier New" size=2>got line [2] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: exiting for the last time</FONT> <BR><FONT 
  face="Courier New" size=2>got line [3] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: exiting for the last time</FONT> <BR><FONT 
  face="Courier New" size=2>got line [10] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: exiting for the last time</FONT> <BR><FONT 
  face="Courier New" size=2>got line [99999] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>pauseProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: invoked</FONT> <BR><FONT face="Courier New" 
  size=2>resumeProducing: exiting for the last time</FONT> <BR><FONT 
  face="Courier New" size=2>got line [bye] from client [IPv4Address(TCP, 
  '127.0.0.1', 51007)]</FONT> <BR><FONT face="Courier New" size=2>goodbye to 
  IPv4Address(TCP, '127.0.0.1', 51007)</FONT> </P></BLOCKQUOTE></BODY></HTML>