Reputation: 211
I'm attempting to add an irc client to a django web application I'm working on. I'd like the server side code for the irc communication to use python and connect through the sockets library. I'll then use gevent-socketio to send and receive data from the irc channel to the client side in the browser. So far I have a very basic gevent-socketio server and client that can be used for realtime broadcasting amongst multiple clients, however, when I start to connect clients to IRC they connect to the IRC server successfully using a nick passed from the client, but then it appears that this is ongoing keepalive/listening process is blocking be from sending any messages from the client.
Python IRC code
import socket
class pycli:
def __init__(self,user):
self.nick = user
self.chan = "#testchannel"
self.owner = "Bluebot"
self.sock = socket.socket()
print "irc conn"
def send_msg(self,message):
self.sock.send("PRIVMSG " + self.chan + " : " + message + "\r\n")
## misc setup
def keep_alive(self):
self.sock.connect(("irc.freenode.net",6667))
self.sock.send("USER " + self.nick + " 0 * :" + self.owner + "\r\n")
self.sock.send("NICK " + self.nick + "\r\n")
while 1:
## keep checking for data
data = self.sock.recv(512)
datalen = len(data.split(" "))
sender = ""
msg_type = ""
msg_rcpt = ""
message = ""
###----------------------------------------------
## reply to keep alive pings
if data[0:4] == "PING":
self.sock.send(data.replace("PING", "PONG"))
if data[0]!=':':
continue
if data.split(" ")[1] == "001":
self.sock.send("MODE " + self.nick + " +B\r\n")
self.sock.send("JOIN " + self.chan + "\r\n")
###-----------------------------------------------
##split and assign data parts
## parse out the actual sender
send_data = data.split(" ")[0]
send_data = send_data[1:]
sender = send_data.split('!')[0]
## mode
msg_type = data.split(" ")[1]
## if it exists get the recipient (room or private)
if datalen > 2:
msg_rcpt = data.split(" ")[2]
## get the actual message body
if datalen > 3:
message = (" ".join(data.split(" ")[3:])).lower()[1:]
print data
I know this functionality is super basic, but I can expand on it once I get it working through the client.
The relevant parts of my server code basically looks like:
def on_login(self, nick):
if self.nick:
self._broadcast('exit', self.nick)
self.nick = nick
self._broadcast('enter', nick)
self.emit('users',
[ ns.nick
for ns in self._registry.values()
if ns.nick is not None ])
t = threading.Thread(target=self.make_start_irc(nick),daemon=True)
t.start()
def on_chat(self, message):
if self.nick:
self._broadcast('chat', dict(u=self.nick, m=message))
self._irc_nicks[self.nick].send_msg("this is a test")
else:
self.emit('chat', dict(u='SYSTEM', m='You must first login'))
def make_start_irc(self,nick):
if nick not in self._irc_nicks.values():
self._irc_nicks[nick] = pycli.pycli(nick)
print self._irc_nicks
self._irc_nicks[nick].keep_alive()
def _broadcast(self, event, message):
for s in self._registry.values():
s.emit(event, message)
def chat(environ, start_response):
if environ['PATH_INFO'].startswith('/socket.io'):
return socketio_manage(environ, { '/chat': ChatNamespace })
else:
return serve_file(environ, start_response)
def serve_file(environ, start_response):
path = os.path.normpath(
os.path.join(public, environ['PATH_INFO'].lstrip('/')))
assert path.startswith(public), path
if os.path.exists(path):
start_response('200 OK', [('Content-Type', 'text/html')])
with open(path) as fp:
while True:
chunk = fp.read(4096)
if not chunk: break
yield chunk
else:
start_response('404 NOT FOUND', [])
yield 'File not found'
if __name__ == "__main__":
from gevent import monkey
monkey.patch_all()
sio_server = SocketIOServer(
('', 8080), chat,
policy_server=False)
t2 = threading.Thread(target=sio_server.serve_forever())
t2.start()
When I eventually give up and use ctrl-C, I see the following stacktrace which leads me to believe something about the way I'm threading is blocking.
Traceback (most recent call last):
File "socketio_test.py", line 92, in <module>
t2 = threading.Thread(target=sio_server.serve_forever())
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/baseserver.py", line 284, in serve_forever
self._stop_event.wait()
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/event.py", line 77, in wait
result = self.hub.switch()
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/hub.py", line 338, in switch
return greenlet.switch(self)
KeyboardInterrupt
If anyone has any idea how I can change the irc process to be non-blocking, or any general suggestions they'd be greatly appreciated.
Upvotes: 1
Views: 121
Reputation: 74675
You should remove the call:
t2 = threading.Thread(target=sio_server.serve_forever())
And properly pass the method:
t2 = threading.Thread(target=sio_server.serve_forever)
Upvotes: 0