Here is my current code:
#!/usr/bin/env python
from twisted.application import internet, service
from twisted.application.service import IServiceMaker, MultiService
from twisted.protocols import basic
from twisted.internet import reactor, protocol, defer
from twisted.internet.protocol import DatagramProtocol
import datetime
class WebPUSH(basic.LineReceiver):
logTemplate = '''
<script type="text/javascript">
pushHandler.addLi('%s')
</script>
'''
def __init__(self):
self.gotRequest = False
def lineReceived(self, line):
if not self.gotRequest:
self.startResponse()
self.gotRequest = True
def startResponse(self):
self.sendLine('HTTP/1.1 200 OK')
self.sendLine('Content-Type: text/html; charset=utf-8')
self.sendLine('')
f = open('index.html', 'r')
self.transport.write( ''.join(f.read()) )
f.close()
self.logTime()
def logTime(self):
self.sendLine( self.logTemplate % datetime.datetime.now() )
#reactor.callLater(2, self.logTime)
class Echo(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
WebPUSH.logTime()
print "received %r from %s:%d" % (data, host, port)
self.transport.write(data, (host, port))
if __name__ == '__main__':
f = protocol.ServerFactory()
f.protocol = WebPUSH
reactor.listenTCP(8080, f)
r开发者_Python百科eactor.listenUDP(9999, Echo())
reactor.run()
As you can see, I am trying to call a method in WebPUSH from Echo when data is received. Because I never actually instantiate WebPUSH it doesn't look like I can easily call this method. I tried converting this to use a multiservice method but that didn't seem to work although I am sure I am doing something wrong.
There aren't (as far as I could google) any good examples on multiservice with twisted or atleast one like this.
Any help will be appreciated.
Echo
instance needs an instance of WebPUSH
protocol to call .logTime()
.
You need to maintain loggers
list, e.g., in main()
:
...
f.loggers = []
echo = Echo()
echo.loggers = f.loggers
...
Add to it in WebPUSH.connectionMade
, remove in WebPUSH.connectionLost
:
def connectionMade(self):
self.factory.loggers.append(self)
def connectionLost(self, reason):
self.factory.loggers.remove(self)
then in Echo.datagramReceived
:
for time_logger in self.loggers:
time_logger.logTime()
user970077, the example in my blog was meant to be a simplified demo to show how the webpush work. Here is what you are trying to do (incorporating JFB suggestions):
#!/usr/bin/env python
from twisted.protocols import basic
from twisted.internet import reactor, protocol, defer
import datetime
class WebPUSH(basic.LineReceiver):
logTemplate = '''
<script type="text/javascript">
pushHandler.addLi('%s')
</script>
'''
def connectionMade(self):
self.factory.listeners.append(self)
self.startResponse()
def connectionLost(self, reason):
self.factory.listeners.remove(self)
def lineReceived(self, line):
self.sendLine( self.logTemplate % line )
def startResponse(self):
self.sendLine('HTTP/1.1 200 OK')
self.sendLine('Content-Type: text/html; charset=utf-8')
self.sendLine('')
with open('index.html', 'r') as f:
self.transport.write( ''.join(f.read()) )
class WebPushFactory(protocol.ServerFactory):
protocol = WebPUSH
def __init__(self):
self.listeners = []
class Echo(protocol.DatagramProtocol):
def __init__(self, listeners):
self.listeners = listeners
def datagramReceived(self, data, (host, port)):
msg = '[%s:%s] %s' % (host, port, data)
for listener in self.listeners:
# udp is not necessarily line-oriented
# so we can:
# 1) feed dataReceived and wait until the line
# delimiter arrives in an udp package
# triggering lineReceived:
#listener.dataReceived( msg )
# or 2) fake a line by calling lineReceived direclty:
listener.lineReceived( msg )
print msg
self.transport.write(data, (host, port))
if __name__ == '__main__':
web = WebPushFactory()
reactor.listenTCP(8080, web)
reactor.listenUDP(9999, Echo(web.listeners))
reactor.run()
And a client to test it (taken from UDP client and server with Twisted Python):
#!/usr/bin/env python
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time
class HeartbeatSender(DatagramProtocol):
def __init__(self, name, host, port):
self.name = name
self.loopObj = None
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
# I am ready to send heart beats
self.loopObj = LoopingCall(self.sendHeartBeat)
self.loopObj.start(2, now=False)
def stopProtocol(self):
"Called after all transport is teared down"
pass
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
def sendHeartBeat(self):
self.transport.write(self.name, (self.host, self.port))
if __name__ == '__main__':
sender = HeartbeatSender("sender", "127.0.0.1", 9999)
reactor.listenMulticast(9998, sender, listenMultiple=True)
reactor.run()
精彩评论