You are not logged in Log in Join
You are here: Home » Members » Lawouach » ZPyIrc

Log in
Name

Password

 
 

ZPyIrc

Overview

Zope comes today with products in many different fields and grows everyday with new products. Nonetheless some fields are empty or almost. IRC was one of these empty fields. Between may and june 2003 I've written an IRC pure-module for python. Some already existed but I wanted to learn Python and the best way was to stick toa project like implementing a RFC. Moreover many existing modules didn't fill my need. That's how pyirc started. From the very beginning of the project I wanted to create a Zope Product such as an IRC client because it was a great way to add something that was missing to Zope and see how Zope works for its Products.

I have written the ZPyIrc product in 10 days. Actually I'm quite proud of it as when I started I didn't know anything about Zope product development. I knew Zope already but not so much I'd say. This means that a Zope or even Python guru might be scared by my coding style. I don't pretend to be a Zope developer guru. I did my best to make this product as well coded as possible but I might be wrong.

ZPyIrc also comes with ZPyIrcSimpleBot which as its name mention is an IRC bot for Zope. Actually, both projects are independant and they don't need each other to live, but they are a great couple in order to set your own nice web-based clients.

Architecture

IRC is a text based protocol. Somewhere you have a server that waits for incoming connections, somewhere else you have some clients which tries to reach the server and connect to it. Note that I used which instead of who as clients are not necesseraly human beings as we'll see with the bot section. Dialog is based on text commands and answer over the network.

Basically the following figure explain simply how ZPyIrc works.

Remember that ZPyIrc is a web-based client for IRC which means that you use its services through a web browser and not with an application like pyirc offers with PyQt or PyGtk. So you connect through a web browser. You could think then that your browser is the effective client of the IRC server and you would be wrong. In fact the web interface is an interface to the real client : ZPyIrc. When you use the web interface to connect to a server, actually the internal machinery will create an object that will handle your states and connection alive. This object is simply an instance of a class which inherits OFS.SimpleItem.Item class in order to get entry point to the Zope machinery. Thus, this object is the real client of the IRC server.

Let's go deeper now.

We've just seen that the web interface was really only an interface for the real client that is managed by Zope. Why do we need Zope to keep trace of the connection ?

HTTP is a stateless protocol which basically means that you can't keep a connection alive through a session. Once your page is loaded the connection with the HTTP server is broken. Not a good thing for a product like ZPyIrc which only works through socket connections that must stay alive as long as clients request it.

So how does ZPyIrc handle that ?

We use the power of Python and Zope of course. Each client owns its socket object that is the way to communicate between itself and the server. Such a socket must beinitiliazed once and stay alive as long as requested. So we use the power of Python that keeps track of every object created while running. This means that while Zope is alive, Python that is running under will keep track internally of every objects created until it is destroyed. Therefore, ZPyIrc module handles a dictionnary of connections that will stay alive as long as they are used within a Zope life, which can mean forever if the Zope server is never stopped.

Some might wonder why I don't keep track of the socket within a Zope object itself instead of doing that. Well because this isn't possible. Zope keeps track of every objects thanks to the pickle module. This module just serializes an object and deserializes it on the fly Zope object. But of course this is not possible with all objects, and definitely not with socket object. That's why I couldn't use that way.

"OK, but hey you said before that you were actually storing instances of class that inherits OFS.SimpleItem.Item !" Yes I do. In fact I can't keep track of the socket connection within a Zope object but I can save any other data I need to achieve my goal of client. This means : nickname, servername, username, realname, channels, text on each channel, etc... This is also this object that I'll call from the browser to retreive or send data through the socket. Each object has an unique ID created with the help of the md5 module of Python.

So here how it basically works :

The manager creates a ZPyIrc object within Zope setting all default variables like the default server, default port, default channel, etc. The ZPyIrc class within the ZPyIrc module inherits from Folder. Within this folder, we will keep track of all connections.

Let's say now that a client wants to connect. He arrives on the index page of the ZPyIrc Folder object and fills the form. Then he clicks on the connect button. When the click is done, an object ZPyIrcConnexion is created. Its Id is unique, this object stores into the global connections dictionnary its own connection (represented by an instance of the pyirc class itself). It tries to connect and if it suceeds, it raises the main chatting page.

Of course, we don't want to put the Zope server on its knees. That's why we have a timeout to close connections that stay alive and inactive too long. Another option of the ZPyIrc object is that you can set a limit of connections you accept on your server. This can be a no limit if sets to -1 or no connection at all if sets to 0. In any case those fields can be changed on the fly.

What will happen when a client quits the server ?

If the client asks explicitely through a quit message, the connection is closed nicely. If he just kills his browser, the manager will have to do it manually through a method of ZPyIrc class called "sweep". This method will delete any non alive objects inside the Folder and any ones alive but out of time. This means that actually, if the client quits nicely, the connection is closed and removed from the global dictionnary but the object itself stays. Thus if the client comes later and the manager didn't already clean the folder, it will avoid to recreate the same object (only if the user gives the same nickname, username and real name).

On the client side, how does it work while an user is chatting? As I said, HTTP is stateless. That mean that we can't open a web page and read asynchronously from the server neither write data. So how does ZPyIrc achieve this task? Thanks to the power of Javascript. Generally speaking many web programmers hate Javascript because it's often non treated the same way by different browsers and because the code is often messy. Moreover ZPyIrc is not only using the Javacript devil but also frames. Why ? Why ? OhWhy ?

Well you can't expect the user to refresh manually his page every second and you can't expect to have a decent chat if you refresh once in a while as well. You need to do it on a regular basis. The reload is necessaray so that we can during the session ask the server if it reads some messages and if so to treat and return them so that the client can handle them. But we don't want to reload the main chat page each time, it wouldn't be usable. So we have two frames. The first one display nothing but just reloads itself every second for example. If it reads data, it does some treatment and displays them on the other frame where it needs to go. This reload can be an issue as the page that reloads itself is about 3Ko. That can be a lot if you have a lot of clients simultanously connected. If someone has a better way to do it please let me know. In any case, the refresh timing is the responsability of the manager of the ZPyIrc object. It can modify it easily within ZPT pages.

ZPyIrcSimpleBot

ZPyIrcSimpleBot is a simple object that tends to be a flexible IRC bot for Zope. It doesn't need ZPyIrc to exist at all. The ZPyIrcSimpleBot module provides a class that inherits Folder. When you create an instance of that class, you create a folder where you'll put Python Scripts and External Methods that will be specific to a message returned by the pyirc module. Then ZPyIrcSimpleBoot will call those scripts and run them with incoming data. You can then do what you want and ask ZPyIrcSimpleBot to send a command or a message to the server or channel specified. This means that the bot doesn't need to be stopped or deleted when you want to add features to it.

Here are some screenshots of the UI. Hell yes it's ugly ! But actually it's up to you to change ZPT pages to fit your own site of course.

Note : ZPyIRc comes with the pyirc module already so you don't need to get it from elsewhere. But if you need the pyirc module itself please don't use that one as it mght exist a newer version on the official site.

Latest Release: 0.1.3
Last Updated: 2003-08-27 14:11:47
Author: Lawouach
License: GPL
Categories: Server
Maturity: Stable

Available Releases

Version Maturity Platform Released
0.1.3 Stable   2003-08-27 00:00:00
  ZPyIrc-0.1.3.tgz (53 K) All md5
0.1.2 Stable   2003-08-25 00:00:00
  ZPyIrc-0.1.2.tgz (52 K) All
0.1.0 Development   2003-07-25 16:36:33
  ZPyIrc-0.1.0.tar.gz (30 K) All