I've been playing around with the Twisted extension and have fooled around with a chat room sort of system. However I want to expand upon it. As of now it only support multi-client chats with usernames ect. But I want to try and use the pyAudio extension to build a sort of VoIP application. I have a clientFactory and a simple echo protocol in the client and a serverFactory and protocol on the server. but I'm not entirely sure how to build off of this. What would be the best way to go about doing something like this?
Code to help if you need it
client.py:
import wx
from twisted.internet import wxreactor
wxreactor.install()
# import twisted reactor
import sys
from twisted.internet import reactor, protocol, task
from twisted.protocols import basic
class ChatFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="WhiteNOISE")
self.protocol = None # twisted Protocol
sizer = wx.BoxSizer(wx.VERTICAL)
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.ctrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER, size=(300, 25))
sizer.Add(self.text, 5, wx.EXPAND)
sizer.Add(self.ctrl, 0, wx.EXPAND)
self.SetSizer(sizer)
self.ctrl.Bind(wx.EVT_TEXT_ENTER, self.send)
def send(self, evt):
self.protocol.sendLine(str(self.ctrl.GetValue()))
self.ctrl.SetValue("")
class DataForwardingProtocol(basic.LineReceiver):
def __init__(self):
self.output = None
def dataReceived(self, data):
gui = self.factory.gui
gui.protocol = self
if gui:
val = gui.text.GetValue()
gui.text.SetValue(val + data)
gui.text.SetInsertionPointEnd()
def connectionMade(self):
self.output = self.factory.gui.text # redirect Twisted's output
class ChatFactory(protocol.ClientFactory):
def __init__(self, gui):
self.gui = gui
self.protocol = DataForwardingProtocol
def clientConnectionLost(self, transport, reason):
reactor.stop()
def clientConnectionFailed(self, transport, reason):
reactor.stop()
if __name__ == '__main__':
app = wx.App(False)
frame = ChatFrame()
frame.Show()
reactor.registerWxApp(app)
reactor.connectTCP("192.168.1.115", 5001, ChatFactory(frame))
reactor.run()
server.py:
from twisted.internet import reactor, protocol
from twisted.protocols import basic
import time
def t():
return "["+ time.strftime("%H:%M:%S") +"] "
class EchoProtocol(basic.LineReceiver):
name = "Unnamed"
def connectionMade(self):
#on client connection made
self.sendLine("WhiteNOISE")
self.sendLine("Enter A Username Below...")
self.sendLine("")
self.count = 0
self.factory.clients.append(self)
print t() + "+ Connection from: "+ self.transport.getPeer().host
def connectionLost(self, reason):
#on client connection lost
self.sendMsg("- %s left." % self.name)
print t() + "- Connection lost: "+ self.name
self.factory.clients.remove(self)
def lineReceived(self, line):
#actions to do on message recive
if line == '/quit':
#close client connection
self.sendLine("Goodbye.")
self.transport.loseConnection()
return
elif line == "/userlist":
#send user list to single client, the one who requested it
self.chatters()
return
elif line.startswith("/me"):
#send an action formatted message
self.sendLine("**" + self.name + ": " + line.replace("/me",""))
return
elif line == "/?":
self.sendLine("Commands: /? /me /userlist /quit")
return
if not self.count:
self.username(line)
else:
self.sendMsg(self.name +": " + line)
def username(self, line):
#check if username already in use
for x in self.factory.clients:
if x.name == line:
self.sendLine("This username is taken; please choose another")
return
self.name = line
self.chatters()
self.sendLine("You have been connected!")
self.sendLine("")
self.count += 1
self.sendMsg("+ %s joined." % self.name)
print '%s~ %s connected as: %s' % (t(), self.transport.getPeer().host, self.name)
def chatters(self):
x = len(self.factory.clients) - 1
s = 'is' if x == 1 else 'are'
p = 'person' if x == 1 else 'people'
self.sendLine("There %s %i other %s connected:" % (s, x, p) )
for client in self.factory.clients:
if client is not self:
self.sendLine(client.name)
self.sendLine("")
def sendMsg(self, message):
#send message to all clients
for client in self.factory.clients:
client.sendLine(t() + message)
class EchoServerFactory(protocol.ServerFactory):
protocol = EchoProtocol
clients = []
if __name__ == "__main__":
reactor.listenTCP(5001, EchoServerFactory())
reactor.run()
Take a look at Divmod Sine, a SIP application server. The basic idea is that you need an additional network server in your application that will support the VoIP parts of the application.
Related
I am trying to build a multiplayer game that uses Python. I am using Tornado to build the client and server. Ideally, what I would like to happen are as follows:
(a) For the client to wait for user input from the command line
(b) When the client gets user input, to send the user input to the server
(c) for the server to simulate some processing(which will be the game engine) on it and send the response back to a client.
The server
"""
Server module for game server
"""
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
import uuid
import json
class Controller(object):
def __init__(self):
self.players = ()
self.connections = ()
def check(self):
return "Hi"
def run_somthing(self, text):
new_text = "Server: " + text
return new_text
class InitMessageHandler(tornado.web.RequestHandler):
def get(self):
user_data = {}
user_data['user_id'] = str(uuid.uuid4())
self.write(json.dumps(user_data))
class GameHandler(tornado.websocket.WebSocketHandler):
def open(self):
# called anytime a new connection with this server is opened
print("Client connected")
print("Client sent: ", self)
if seif not in self.application.controller.connections:
self.application.controller.connections.add(self)
def on_message(self):
# called anytime a new message is received
pass
def check_origin(self, origin):
return True
def on_close(self):
# called a websocket connection is closed
if self in self.application.controller.connections:
self.application.controller.connections.remove(self)
class Server(tornado.web.Application):
def __init__(self):
self.controller = Controller()
handlers = [
(r"/join", InitMessageHandler),
(r"/game", GameHandler)
]
tornado.web.Application.__init__(self, handlers)
if __name__ == "__main__":
tornado.options.parse_command_line()
try:
application = Server()
server = tornado.httpserver.HTTPServer(application)
server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
tornado.ioloop.IOLoop.instance().stop()
print("closed")
The client
"""
Client module for the game clients(Players)
"""
import tornado.ioloop
import tornado.websocket
import requests
import json
import sys
import tornado.gen
class Client(object):
def __init__(self, join_url, play_url):
self.wsconn = None
self.join_url = join_url
self.play_url = play_url
#self.io_loop = tornado.ioloop.IOLoop.instance()
#self.io_loop.add_handler(sys.stdin, self.handle_user_input, tornado.ioloop.IOLoop.READ)
self.user_details = {}
self.has_initialised = False
#self.io_loop.start()
self.main()
def get_user_input(self, question=None):
str_choice = input(question)
while any((str_choice is None, not str_choice.strip())):
print("You entered an empty answer")
str_choice = input(question)
return str_choice
def _merge_dicts(*dict_args):
"""
Given any number of dicts, shallow copy and merge into a new dict,
precedence goes to key value pairs in latter dicts.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
def generate_wsmessage(self):
msg_line = input("Enter message to send to server")
while any((msg_line is None, not msg_line.strip())):
print("You entered an empty answer")
msg_line = input("Enter message to send to server")
msg = {}
msg['message'] = msg_line
msg_to_send = self._merge_dicts(self.user_details, msg)
return json.dumps(msg_to-send)
def init(self):
print("Heh")
username = self.get_user_input("What is your username? ")
print("Getting initial user details")
req = requests.get(self.join_url)
response = json.loads(req.text)
print(response)
self.user_details['name'] = username
self.user_details['user_id'] = response['user_id']
self.has_initialised = True
def server_recv(self, msg):
print("Server has connected on websocket socket with msg=", msg)
#tornado.gen.coroutine
def connect_on_websocket(self):
try:
self.wsconn = yield tornado.websocket.websocket_connect(self.play_url, on_message_callback=self.server_recv)
except Exception as e:
print("Connection error: {}".format(e))
else:
print("Connected")
#tornado.gen.coroutine
def send_wsmessage(self):
msg = self.generate_wsmessage()
yield self.wsconn.write_message(msg)
#tornado.gen.coroutine
def communicate_with_websocket(self):
self.send_wsmessage()
while True:
recv_msg = yield self.wsconn.read_message()
if recv_msg is None:
self.wsconn.close()
break
yield tornado.gen.sleep(0.1)
self.send_wsmessage()
print("IoLoop terminate")
def main(self):
choice = input("Do you want to continue(y/n)? ")
if choice == "y" and self.has_initialised == False:
print("Yup")
self.init()
if self.has_initialised == True:
self.connect_on_websocket()
self.communicate_with_websocket()
if __name__ == "__main__":
try:
client = Client("http://localhost:8888/join", "ws://localhost:8888/game")
tornado.ioloop.IOLoop.instance().start()
except (SystemExit, KeyboardInterrupt):
print("Client closed")
From reading the some examples online, I came up the code above, but it is not working. So my main question is
how to make Tornado coroutines work with stdin(command line input)
My other questions are:
(a) Is the code I have written the right way to work with Tornado coroutines or not?
(b) If it is not, could you ELI5? Also I would appreciate code examples that really use Tornado in interesting ways(at any intermediate level) so that I can learn from them.
(c) Is there a more intuitive way to do what I want to do,in Python? Like a Flask+Gevents or Twisted version or just pure sockets version that might be easier to work with?
Thanks for your help.
EDIT: Flan pointed out some errors for me and I fixed it and it works now.
As I can see at the moment, problem is not in stdin interaction, but your wrong way of using coroutines. Your connect_on_websocket and communicate_with_websocket functions are coroutines but you are using them as a plain functions and it won't work. I propose these changes.
Make main() coroutine (add decorator), don't call it, remove from the Client.__init__().
In name=main block schedule client.main() invocation with tornado.ioloop.IOLoop.instance().add_callback(client.main).
In main and all your code change coroutine-functions' (with #tornado.gen.coroutine) calls to yield, for example yield self.connect_on_websocket() instead of just self.connect_on_websocket()
That should be sufficient so you can proceed your development further.
The edited code is
The server:
"""
Server module for game server
"""
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
import uuid
import json
class Controller(object):
def __init__(self):
self.players = set()
self.connections = set()
def check(self):
return "Hi"
def run_somthing(self, text):
new_text = "Server: " + text
return new_text
class InitMessageHandler(tornado.web.RequestHandler):
def get(self):
print("Client has asked for initial details")
user_data = {}
user_data['user_id'] = str(uuid.uuid4())
self.write(json.dumps(user_data))
class GameHandler(tornado.websocket.WebSocketHandler):
def open(self):
# called anytime a new connection with this server is opened
print("Client connected")
print("Client sent: ", self)
if self not in self.application.controller.connections:
self.application.controller.connections.add(self)
def on_message(self, message):
# called anytime a new message is received
print("Received from client ,msg=", message)
msg = "Server: " + message
self.write_message(json.dumps(msg))
def check_origin(self, origin):
return True
def on_close(self):
# called a websocket connection is closed
if self in self.application.controller.connections:
self.application.controller.connections.remove(self)
class Server(tornado.web.Application):
def __init__(self):
self.controller = Controller()
handlers = [
(r"/join", InitMessageHandler),
(r"/game", GameHandler)
]
tornado.web.Application.__init__(self, handlers)
if __name__ == "__main__":
tornado.options.parse_command_line()
try:
application = Server()
server = tornado.httpserver.HTTPServer(application)
server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
tornado.ioloop.IOLoop.instance().stop()
print("Server closed")
The client
import tornado.ioloop
import tornado.websocket
import requests
import json
import sys
import tornado.gen
class Client(object):
def __init__(self, join_url, play_url):
self.wsconn = None
self.join_url = join_url
self.play_url = play_url
self.user_details = {}
def get_user_input(self, question=None):
str_choice = input(question)
while any((str_choice is None, not str_choice.strip())):
print("You entered an empty answer")
str_choice = input(question)
return str_choice
def _merge_dicts(*dict_args):
"""
Given any number of dicts, shallow copy and merge into a new dict,
precedence goes to key value pairs in latter dicts.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
def generate_wsmessage(self):
msg_line = self.get_user_input("Enter message to send to server: ")
msg = {}
msg['message'] = msg_line
msg['user_id'] = self.user_details['user_id']
msg['user_name'] = self.user_details['user_name']
print("Message to send: ", msg)
return json.dumps(msg)
def init(self):
print("Heh")
username = self.get_user_input("What is your username? ")
print("Getting initial user details")
req = requests.get(self.join_url)
response = json.loads(req.text)
print(response)
self.user_details['user_name'] = username
self.user_details['user_id'] = response['user_id']
#tornado.gen.coroutine
def connect_on_websocket(self):
try:
self.wsconn = yield tornado.websocket.websocket_connect(self.play_url)
except Exception as e:
print("Connection error: {}".format(e))
else:
print("Server has connected to ")
yield self.send_wsmessage()
#tornado.gen.coroutine
def send_wsmessage(self):
msg = self.generate_wsmessage()
if not self.wsconn:
raise RuntimeError('Web socket connection is closed.')
yield self.wsconn.write_message(json.dumps(msg))
yield self.communicate_with_websocket()
#tornado.gen.coroutine
def communicate_with_websocket(self):
recv_msg = None
while True:
recv_msg = yield self.wsconn.read_message()
if recv_msg is None:
self.wsconn.close()
break
print("Server has replied with message=", recv_msg)
yield self.send_wsmessage()
print("IoLoop terminate")
#tornado.gen.coroutine
def main(self):
choice = input("Do you want to continue(y/n)? ")
if choice == "y":
print("Yup")
self.init()
yield self.connect_on_websocket()
if choice == "n":
sys.exit()
if __name__ == "__main__":
try:
client = Client("http://localhost:8888/join", "ws://localhost:8888/game")
tornado.ioloop.IOLoop.instance().add_callback(client.main)
tornado.ioloop.IOLoop.instance().start()
except (SystemExit, KeyboardInterrupt):
print("Client closed")
For (a), (b) check out here. For (c), another time.
I'm working with this example of an iPhone Chart Server and all is working as expected.
What I wanted to ask is if and how I can use message(self, message) outside the IphoneChat class...
For example if I have an event triggering every hour I want to be able to send everyone connected a message or if I want to take the server down to send a 'global' announcement, do I have to put all the code within the IphoneChat class?
The server.py is this:
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
self.factory.clients.append(self)
print "clients are ", self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
# define message handling...
def dataReceived(self, data):
a = data.split(':')
print a
if len(a) > 1:
command = a[0]
content = a[1]
msg = ""
if command == "iam":
#msg = content + " has joined"
msg = "test1"
elif command == "toggle":
#msg = command + ": " + content
msg = "test2"
elif command == "msg":
msg = command + ": " + content
print msg
for c in self.factory.clients:
c.message(msg)
def message(self, message):
self.transport.write(message + '\n')
rt = pollTimer.RepeatedTimer(3, NotifyAllFunction)
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
reactor.listenTCP(6035, factory)
print "chat server started"
reactor.run()
Adding the polling module:
from threading import Timer
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.start()
def _run(self):
self.is_running = False
self.start()
self.function(*self.args, **self.kwargs)
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False
Let's say you registered a callback to be executed after some time, then you can simple access all the clients from factory.clients and send them a message using their .transport.write() method:
from twisted.internet import task
...
# Rest of the code
...
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
def broadcast(message):
for client in factory.clients:
client.transport.write(message + '\n')
event = task.LoopingCall(broadcast, 'Ping to all users')
event.start(60*60) # call every hour
reactor.listenTCP(6035, factory)
print "chat server started"
reactor.run()
Can you anyone please help me (noob) call the broadcast function from class BroadcastServerFactory in class process, as per attached code
I have tried so many methods of call a function from another class, but no solution
import time, sys
from apscheduler.scheduler import Scheduler
import threading
import socket
from twisted.internet import reactor
from twisted.python import log
from twisted.web.server import Site
from twisted.web.static import File
from autobahn.websocket import WebSocketServerFactory, \
WebSocketServerProtocol, \
listenWS
class process(threading.Thread):
def __init__(self, buffer3):
threading.Thread.__init__(self)
self.setDaemon(True)
self.buffer3 = buffer3
def run(self):
factory.broadcast("I don't know what I'm doing!")
class BroadcastServerProtocol(WebSocketServerProtocol):
def onOpen(self):
self.factory.register(self)
def onMessage(self, msg, binary):
if not binary:
self.factory.broadcast("'%s' from %s" % (msg, self.peerstr))
def connectionLost(self, reason):
WebSocketServerProtocol.connectionLost(self, reason)
self.factory.unregister(self)
class BroadcastServerFactory(WebSocketServerFactory):
"""
Simple broadcast server broadcasting any message it receives to all
currently connected clients.
"""
def __init__(self, url, debug = False, debugCodePaths = False):
WebSocketServerFactory.__init__(self, url, debug = debug, debugCodePaths = debugCodePaths)
self.clients = []
self.tickcount = 0
self.tick()
def tick(self):
self.tickcount += 1
self.broadcast("'tick %d' from server" % self.tickcount)
reactor.callLater(1, self.tick)
def register(self, client):
if not client in self.clients:
print "registered client " + client.peerstr
self.clients.append(client)
def unregister(self, client):
if client in self.clients:
print "unregistered client " + client.peerstr
self.clients.remove(client)
def broadcast(self, msg):
print "broadcasting message '%s' .." % msg
for c in self.clients:
c.sendMessage(msg)
print "message sent to " + c.peerstr
class BroadcastPreparedServerFactory(BroadcastServerFactory):
"""
Functionally same as above, but optimized broadcast using
prepareMessage and sendPreparedMessage.
"""
def broadcast(self, msg):
print "broadcasting prepared message '%s' .." % msg
preparedMsg = self.prepareMessage(msg)
for c in self.clients:
c.sendPreparedMessage(preparedMsg)
print "prepared message sent to " + c.peerstr
def testing():
buffer2 - "hello"
myDisplay = process(buffer2)
myDisplay.start()
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'debug':
log.startLogging(sys.stdout)
debug = True
else:
debug = False
level_scheduler = Scheduler()
level_scheduler.add_interval_job(testing, seconds=5)
level_scheduler.start()
#ServerFactory = BroadcastServerFactory
ServerFactory = BroadcastPreparedServerFactory
factory = ServerFactory("ws://localhost:9000",
debug = debug,
debugCodePaths = debug)
factory.protocol = BroadcastServerProtocol
factory.setProtocolOptions(allowHixie76 = True)
listenWS(factory)
webdir = File(".")
web = Site(webdir)
reactor.listenTCP(8080, web)
reactor.run()
Thanks
Pass the class instance of BroadcastServerFactory to be called to the class instance that calls it process on creation
class process(threading.Thread):
def __init__(self, buffer3m, broadcast_server_factory):
threading.Thread.__init__(self)
self.setDaemon(True)
self.buffer3 = buffer3
self.factory = broadcast_server_factory
def run(self):
self.factory.broadcast("I don't know what I'm doing!")
and then call it (it's assigned as self.factory in the run statement. I can't see where you create a process class in your __main__ but it will be created with something like
p = process(buffer, factory)
Aside: Using capital letters for class names is considered good form in python process -> Process
My goal here is to make a simple server handling TCP message like "process My String" that send "My String" to be processed by a quite time taking operation called (here slowFunction). Here I'm calling this function through deferToThread but nothing seems to happened : the defered's callback messages doesn't show up anywhere (breakpoints show it's never called) and the print in the function aren't displayed (breakpoints show it's never called)
from twisted import protocols
from twisted.protocols import basic
from twisted.internet import threads, protocol, reactor
from twisted.application import service, internet
import re
import time
def slowFunction(arg):
print "starting process"
time.sleep(1)
print "processed "+arg
class MySimpleServer(basic.LineReceiver):
PROCESS_COMMAND = "process (.*)" #re pattern
processFunction = slowFunction
clients = []
def connectionMade(self):
print "Client connected"
MySimpleServer.clients.append(self)
def connectionLost(self, reason):
print "Client gone"
MySimpleServer.clients.remove(self)
def onProcessDone(self):
self.message("Process done")
def onError(self):
self.message("Process fail with error")
def lineReceived(self, line):
processArgumentResult = re.search(MySimpleServer.PROCESS_COMMAND, line)
if not processArgumentResult == None:
processArgument = processArgumentResult.groups()[0]
deferred = threads.deferToThread(MySimpleServer.processFunction, processArgument)
deferred.addCallback(self.onProcessDone)
deferred.addErrback(self.onError)
self.message("processing your request")
else:
print "Unknown message line: "+line
def message(self, message):
self.transport.write(message + '\n')
if __name__ == '__main__':
factory = protocol.ServerFactory()
factory.protocol = MySimpleServer
factory.client = []
reactor.listenTCP(8000, factory)
reactor.run()
I've got some help by the guys of twisted irc
The points are : the callback (onProcessDone and onError) are supposed to take a result argument, and the function called by deferToThread will receive self as an argument (it should one of the MySimpleServer class' method).
The final code is now :
from twisted import protocols
from twisted.protocols import basic
from twisted.internet import threads, protocol, reactor
from twisted.application import service, internet
import re
import time
def slowFunction(arg):
print "starting process"
time.sleep(20)
print "processed "+arg
class MySimpleServer(basic.LineReceiver):
PROCESS_COMMAND = "process (.*)" #re pattern
clients = []
def connectionMade(self):
print "Client connected"
MySimpleServer.clients.append(self)
def connectionLost(self, reason):
print "Client gone"
MySimpleServer.clients.remove(self)
def onProcessDone(self, result):
self.message("Process done")
def onError(self, result):
self.message("Process fail with error")
def processFunction(self, processArgument):
slowFunction(processArgument)
def lineReceived(self, line):
processArgumentResult = re.search(MySimpleServer.PROCESS_COMMAND, line)
if not processArgumentResult == None:
processArgument = processArgumentResult.groups()[0]
deferred = threads.deferToThread(self.processFunction, processArgument)
deferred.addCallback(self.onProcessDone)
deferred.addErrback(self.onError)
self.message("processing your request")
else:
print "Unknown message line: "+line
def message(self, message):
self.transport.write(message + '\n')
if __name__ == '__main__':
factory = protocol.ServerFactory()
factory.protocol = MySimpleServer
factory.client = []
reactor.listenTCP(8000, factory)
reactor.run()
Another way you could've done this is with staticmethod; this is the only legitimate use for it.
class MySimpleServer(basic.LineReceiver):
processFunction = staticmethod(slowFunction)
I've managed to connect to usb modem and a client can connect via tcp to my reactor.listenTCP,the data received from modem will be send back to client. I'm want to take dataReceived from client and send this to modem..I'm struggling to get this to work.Any help will be highly appreciated! the code:
from twisted.internet import win32eventreactor
win32eventreactor.install()
from twisted.internet import reactor
from twisted.internet.serialport import SerialPort
from twisted.internet.protocol import Protocol, Factory
from twisted.python import log
import sys
log.startLogging(sys.stdout)
client_list = []#TCP clients connecting to me
class USBClient(Protocol):
def connectionFailed(self):
print "Connection Failed:", self
reactor.stop()
def connectionMade(self):
print 'Connected to USB modem'
USBClient.sendLine(self, 'AT\r\n')
def dataReceived(self, data):
print "Data received", repr(data)
print "Data received! with %d bytes!" % len(data)
#check & perhaps modify response and return to client
for cli in client_list:
cli.notifyClient(data)
pass
def lineReceived(self, line):
print "Line received", repr(line)
def sendLine(self, cmd):
print cmd
self.transport.write(cmd + "\r\n")
def outReceived(self, data):
print "outReceived! with %d bytes!" % len(data)
self.data = self.data + data
class CommandRx(Protocol):
def connectionMade(self):
print 'Connection received from tcp..'
client_list.append(self)
def dataReceived(self, data):
print 'Command receive', repr(data)
#Build command, if ok, send to serial port
#????
def connectionLost(self, reason):
print 'Connection lost', reason
if self in client_list:
print "Removing " + str(self)
client_list.remove(self)
def notifyClient(self, data):
self.transport.write(data)
class CommandRxFactory(Factory):
protocol = CommandRx
def __init__(self):
client_list = []
if __name__ == '__main__':
reactor.listenTCP(8000, CommandRxFactory())
SerialPort(USBClient(), 'COM8', reactor, baudrate='19200')
reactor.run()
Your problem is not about twisted, but about python. Read this FAQ entry:
How do I make input on one connection result in output on another?
Thing is, if you want to send stuff to a TCP-connected client in your serial-connected protocol, just pass to the protocol a reference to the factory, so you can use that reference to make the bridge.
Here's some example code that roughly does this:
class USBClient(Protocol):
def __init__(self, network):
self.network = network
def dataReceived(self, data):
print "Data received", repr(data)
#check & perhaps modify response and return to client
self.network.notifyAll(data)
#...
class CommandRx(Protocol):
def connectionMade(self):
self.factory.client_list.append(self)
def connectionLost(self, reason):
if self in self.factory.client_list:
self.factory.client_list.remove(self)
class CommandRxFactory(Factory):
protocol = CommandRx
def __init__(self):
self.client_list = []
def notifyAll(self, data):
for cli in self.client_list:
cli.transport.write(data)
When initializing, pass the reference:
tcpfactory = CommandRxFactory()
reactor.listenTCP(8000, tcpfactory)
SerialPort(USBClient(tcpfactory), 'COM8', reactor, baudrate='19200')
reactor.run()
Thanks, got it to work.Could not get def notifyAll to send data to my modem..did it like this:for cli in client_list: cli.transport.write(data)
new code:
import sys
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.protocol import Protocol
from twisted.internet.serialport import SerialPort
from twisted.python import log
log.startLogging(sys.stdout)
client_list = []#TCP clients connecting to me
usb_list = []
class USBClient(Protocol):
def __init__(self, network):
self.network = network
self.usb_list = []
def connectionFailed(self):
print "Connection Failed:", self
reactor.stop()
def connectionMade(self):
usb_list.append(self)
print 'Connected to USB modem'
USBClient.sendLine(self, 'AT\r\n')
def dataReceived(self, data):
print "Data received", repr(data)
print "Data received! with %d bytes!" % len(data)
for cli in client_list:
cli.transport.write(data)
#self.network.notifyAll(data)# !!AArgh..!Could not get this to work
pass
def lineReceived(self, line):
print "Line received", repr(line)
def sendLine(self, cmd):
print cmd
self.transport.write(cmd + "\r\n")
def outReceived(self, data):
print "outReceived! with %d bytes!" % len(data)
self.data = self.data + data
class CommandRx(Protocol):
def connectionMade(self):
print 'Connection received from tcp..'
client_list.append(self)
def dataReceived(self, data):
print 'Command receive', repr(data)
for usb in usb_list:
usb.transport.write(data)
def connectionLost(self, reason):
print 'Connection lost', reason
if self in client_list:
print "Removing " + str(self)
client_list.remove(self)
class CommandRxFactory(Factory):
protocol = CommandRx
def __init__(self):
self.client_list = []
def notifyAll(self, data):
for cli in self.client_list:
cli.transport.write('yipee')
if __name__ == '__main__':
tcpfactory = CommandRxFactory()
reactor.listenTCP(8000, tcpfactory)
SerialPort(USBClient(tcpfactory), '/dev/ttyUSB4', reactor, baudrate='19200')
reactor.run()