I currently trying to convert an application based on twisted to the twistd Twisted Application framework (TAC).
The application works if I start the .py, but not with the "twistd -noy zmq2tcp.tac" daemon. The ZMQ connections seems properly opened, but if started with the tac file it does not Listen on port 2323.
Please explain me the reason why in this case the listenTCP works but not the internet.TCPServer
The zmq2tcp.tac file:
#!/usr/bin/python
# **- encoding: utf-8 -**
from twisted.application import internet, service
from twisted.application.service import Application
from txzmq import ZmqFactory, ZmqEndpoint, ZmqSubConnection, ZmqPushConnection
from zmq2tcp import *
LISTEN_PORT = 2323
class ListenService(service.Service):
def __init__(self):
self.zf = ZmqFactory()
self.minidoFactory = MinidoServerFactory()
def startService(self):
self.sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
self.push = ZmqEndpoint('connect', 'tcp://localhost:5558')
self.subconn = ZmqSubConnection(self.zf, self.sube)
self.subconn.subscribe('')
# Create the resource
self.minidoFactory.pushconn = ZmqPushConnection(self.zf, self.push)
self.subconn.gotMessage = self.minidoFactory.send2tcp
return internet.TCPServer(LISTEN_PORT, self.minidoFactory)
def stopService(self):
del self.sube
del self.push
del self.subconn
application = Application('ZMQ2TCP')
service = ListenService()
service.setServiceParent(application)
The zmq2tcp.py file:
#!/usr/bin/env python
# **- encoding: utf-8 -**
"""
Minido-Unleashed is a set of programs to control a home automation
system based on minido from AnB S.A.
Please check http://kenai.com/projects/minido-unleashed/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***
This program connects to a STOMP server, and allow dual way communication
with the minido bus, checking the validity of the packet before sending.
"""
###############################################################################
from __future__ import print_function
from twisted.application import internet, service
from twisted.internet.protocol import Protocol, ReconnectingClientFactory
from twisted.internet.protocol import Factory
# Other imports
import datetime
import time
import sys
import msgpack
# minido
from protocol import *
# txZMQ
from txzmq import ZmqFactory, ZmqEndpoint, ZmqPubConnection, ZmqSubConnection, ZmqPushConnection
MINIDO_LISTEN_PORT = 2323
class MinidoServerFactory(Factory):
def __init__(self):
self.connections = []
def startedConnecting(self, connector):
print('Started to connect.')
def buildProtocol(self, addr):
return MinidoProtocol(self)
def clientConnectionLost(self, connector, reason):
print('Lost connection. Reason:', reason)
ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def clientConnectionFailed(self, connector, reason):
print('Connection failed. Reason:', reason)
ReconnectingClientFactory.clientConnectionFailed(self, connector,
reason)
def recv_message(self, message):
print(': TCP to STOMP : %s' % (' '.join(map(lambda i: '{0:02X}'.format(i),message))))
pushconn.push(msgpack.packb(message))
def send2tcp(self, rawmessage, tag):
message = msgpack.unpackb(rawmessage)
if type(message) is tuple:
print(": STOMP to %i TCP client(s) : %s" % (
len(self.connections),
' '.join(map(lambda i: '{0:02X}'.format(i),message))))
for conn in self.connections:
conn.send_data(message)
if __name__ == '__main__':
from twisted.internet import reactor
zf = ZmqFactory()
minidoFactory = MinidoServerFactory()
sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
subconn = ZmqSubConnection(zf, sube)
subconn.subscribe('')
subconn.gotMessage = minidoFactory.send2tcp
push = ZmqEndpoint('connect', 'tcp://localhost:5558')
minidoFactory.pushconn = ZmqPushConnection(zf, push)
reactor.listenTCP(MINIDO_LISTEN_PORT, minidoFactory)
reactor.run()
The problem is that in your ListenService.startService
you are creating and returning a TCPServer
service, but you are not starting that service.
IService.startService
does not return a value, so rather than return internet.TCPServer(LISTEN_PORT, self.minidoFactory)
, do internet.TCPServer(LISTEN_PORT, self.minidoFactory).startService()
.
This has an obvious problem though, which is that your stopService
will then not remember where that TCPServer
is to stop it later. It would be better to factor this to create the TCPServer
as soon as possible, and start/stop it along with your service, like this:
class ListenService(service.Service):
def __init__(self):
self.zf = ZmqFactory()
self.minidoFactory = MinidoServerFactory()
self.tcpService = internet.TCPServer(LISTEN_PORT, self.minidoFactory)
def startService(self):
self.sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
self.push = ZmqEndpoint('connect', 'tcp://localhost:5558')
self.subconn = ZmqSubConnection(self.zf, self.sube)
self.subconn.subscribe('')
# Create the resource
self.minidoFactory.pushconn = ZmqPushConnection(self.zf, self.push)
self.subconn.gotMessage = self.minidoFactory.send2tcp
self.tcpService.startService()
def stopService(self):
del self.sube
del self.push
del self.subconn
return self.tcpService.stopService()