I’m doing some multiuser/player development using the Palabre Socket Server, a nice XML socket server for Flash written in Python.

The documentation is a bit spotty, as it’s primarily the work of a lone developer who choses to code more often than document, so I combed through the FAQ and the Forums and the News Posts and assembled this document, which I will try to update as I discover new things.

This doc is for reference only, and I’m not an expert on this software, so your best bet for questions is the Palabre Forums.




To download Palabre Server or client go to the Download Page. You may also check the Sourceforge Project Page for mirrors

New: Flow Diagrams

I’ve started making a flow diagram of the Palabre systems to help get my head around what it’s doing. Here’s the work so far:

Starting the Server  |  Parsing Incoming Data Client Triggered Actions (1) Client Triggered Actions (2)

(These images are formated to be printed out on legal paper or viewed on a 1600×1200 display)

You can also download the original Visio document.

Which XML node can i send and receive ?

This is a list of simple nodes to connect to the server and send simple messages.
 

Connection with nickname and optionnaly password for root
SEND>  <connect nickname="KoolBoy" [ password="YYY" ] />

Answer from the server (nickname in use or non acceptable)
RECEIVE>  <connect isok="1" />

If you want to check the connection
SEND>  <ping />

The server should answer :
RECEIVE>  <pong />

Asking for room list
SEND>  <getrooms />

Rooms list (also supports sub-rooms, operator mode for some clients in rooms, params in rooms (title, locked, …)
RECEIVE> <rooms nb="2" ><room name="XXX" clients="5" /><room clients="20" name="YYY" /></rooms>


Asking to join Room XXX (if room does not exists it is created then)

SEND>  <join room="XXX" />

Room Joined
RECEIVE> <joined room="XXX" />

And the list of clients for this room
SEND>  <clients room="XXX" nb="5" > <client name="Toto" /> <client name="Titi" /> […] </clients>

Joined/Left Information

RECEIVE> <client name="Nickname" joined="Lobby" /> 
RECEIVE> <client name="Nickname" left="Lobby" />

Now when you change/add a room param the full list is not sent back, only the modified param.

And now, the room creator may set the room params as "open"  to everybody with :

<setparam name="openParams" value="True" />
<setparam name="openParams" value="False" />

If set to "true" (or "1"), anybody can use <setparam /> and <removeparam /> in this room

If set to false, only the room creator can do it.

<setparam name="color" value="blue" />
and remove :
<removeparam name="color" />

 UPDATE: it seems the syntax has changed a bit:

<setparam room="roomname" name="color" value="blue" />

<removeparam room="roomname" name="color" />

There are a few others like:

<addchild /> to add a sub-room , or

<setparam /> / <removeparam /> to set parameters for the room,
<leave /> / <quit /> to leave a room or disconnect , …

<broadcast /> / <shutdown /> / <getinfo />

 

# Leaving a room
node == "leave":

# Setting a param for a room
node == "setparam":

# removing a param from a room
node == "removeparam":

# Adding or changing Client Param
node == "clientparam":

# adding a child room
node == "addchild":

To create a sub room use the following node :

<addchild parentroom="nameoftheexistingroom" childroom="nameofthenewroom" />

and you will receive something like :

<room name="nameofthenewroom" clients="2" parent="nameoftheexistingroom" >
</room>

 
# Shutdown server
node == "shutdown":
# Must Be root

# Kick User from server nickName="XYZ"
node == "rmuser":
# Must be root
attribute : (’nickName’):

# Get Informations about a room="XYZ"
node == "getinfo":
# Must be root
attribute : (’room’):

# This can possibly be any node with attribute that tells me to send
# this exact same node to the clients or Room
# I prefer to encapsulate everything in a MSG node,
# but obviously people like to have their own nodes
attrs.has_key(’toroom’) or attrs.has_key(’toclient’) or attrs.has_key(’r') or attrs.has_key(’c'):
if node != "error":

And you can send messages to client directly
(don’t need to join a specific room for two people)

<msg toclient="Nicknameoftheother">Blabla</msg>
or
<m c="Nicknameoftheother">blabla</m>

 

Custom Nodes works exactly as MSG nodes

You can pass toroom/toclient/r/c params to tell Palabre who to send it too but the name of the node is up to you !
So it’s easier to send Messages/Position/Whatever information :

<msg toroom="X" >Hi everyone</msg>
<position toroom="X"><x>12</x><y>15</y></position>

Sub XML nodes allow you to encapsulate XML subnodes in <msg> or whatever nodes

<msg toroom="X" ><title>Hi everyone</title><content>Bla bla bla bla bla bla</content></msg>
<position toroom="X"><x>12</x><y>15</y></position> 

 

Sending a message "msg" or "m"

(Param "c" or "toclient" -> the message is only delivered to one client)
(Param "r" or "toroom" is delivered to entire room)
(Param "b" or "back" tells the server to send the same message back to the send)
(Param "broadcast" sends to everyone)

SEND> <m r="XXX" >Hello everyone i’m very happy to join you all!</m>
RECEIVE>  <m f="Toto" r="XXX">Hello KoolBoy glad to meet you!</m>
RECEIVE>  <m f="Titi" r="XXX">Hi how are you KoolBoy ?</m>
SEND>  <m r="XXX" >Have to go ! Bye !</m>
SEND>  <leave r="XXX" />

 

Setting Clients Params

<clientparam name="Avatar" value="girlwithlonghair2" />

 And everyone receives :

<clientparam r="Lobby" name="Avatar"
value="girlwithlonghair2" f="Nickname" /> 

 Or when you join a new room you receives everyone’s params:

<clients room="Lobby" nb="1">

  <client name="Nickname">

     <param name="Avatar" value="girlwithlonghair2" />

     <param name="HairColor" value="blue" />

     <param name="posX" value="12" />

     <param name="posY" value="64" />

  </client>

  <client name="OtherNickname">

     <param name="Avatar" value="boywithshorthair1" />

     <param name="HairColor" value="green" />

     <param name="posX" value="15" />

     <param name="posY" value="65" />

  </client>

</clients>

Database Connectivity

Database identification supports all the databases modules of AdoDB . If you need to know who is connecting to your server, and have for example, a Mysql database with logins and passwords,
you can enable database Support.

odbc    access    mssql    mysql    mxodbc    mxoracle   oci8   odbc    odbc_mssql    postgres    vfp    sqlite 

If you enable it you need to have AdoDb Python and the required DB module installed .
(view  : http://phplens.com/lens/adodb/adodb-py-docs.htm )

With compiled Win32 version, DB identification works with Mysql,PostgreSQL, and SqlLite because of modules Licences. If you want other Databases with Win32 you’ll have to use the Source version and install the correct module.

Currently under Windows, Postgresql support is buggy.
Under other systems (non compiled palabre versions) you need to have the python Adodb module installed
and the correct database module installed (ex: for mysql : MysqlDB, for Posgresql : PsycoPg, …)

For full list and informations, please see :
http://phplens.com/lens/adodb/adodb-py-docs.htm#databases

To enable this support, open palabre.conf and in the section [database] change :

checkpassword = false

to

checkpassword = true

Then fill the lines bellow according to your database informations

dbType = mysql
dbHost = localhost
dbUser = root
dbPassword =
dbDatabase = test

And specify the request to be used to connect

dBRequest = SELECT * FROM t_logins WHERE login_nickname LIKE [LOGIN] AND login_password LIKE MD5([PASSWORD])

[LOGIN] and [PASSWORD] will automaticaly be replaced with the "nickname" and "password" attributes of the connect node

So you can now use :

<connect nickname="toto" password="str0ngp4ssW0rd" />

to connect.

How to Connect from Flash

Simple Actionscript code to connect to the server.

 

XML.prototype.ignoreWhite = true;

/* Create a new XMLSocket Object */
x = new XMLSocket();
x.ignoreWhite = true;

/* Define an handler function to check connection */
x.onConnect = function (status) {

    if(status) {
        trace(’Connection OK’);

        /* If connection is OK then we can identify and start sending XML */
        _
root.x.send(’<connect nickname="test_’+random(30)+’" ></connect>’);
    } else {
        trace(’No Connection’);
    }
}

/* Define an handler function to trace incoming XML */
    x.onXML = function (xmlNode) {
    trace(’Just Received : ‘+xmlNode);
}

/* Then start the connection, adjust IP and port to reflect the server information */

x.connect(’127.0.0.1′,2468);


 

 

Modules

How to write a module?

1. in the "modules" subdirectory create a file "yourModule.py"
2. In that file create a class yourModule

class yourModule:
    def __init__(self,palabreServer):
        self.server = palabreServer
        self.name = "yourModule"

3. Then specify when your module should be called.
Two options are available : self.server.registerAction() and seld.server.registerNode()

If you want your plugin to be called every time Palabre executes a specific action (example when server startup, when a client connects, when a client Leaves, when a client sends a password for connection, …)

Example : Do something when server starts :

Then add in your __init__ method :

self.server.registerAction(’onStartup’,self.name)

And Create a method called : ‘onStartup’

def onStartup(self,params):
    # Do something
    self.server.logger.info(’My Module is loaded’)
    return

If you want to add an action when clients sends a specific node, add in __init__ :

self.server.regsiterNode(’mynode’,self.name):

And create a method called ‘doNode’

def doNode(self,nodeName,node, client):
    if nodeName == ‘mynode’:
        client.clientSendMessage(’<anynode>You sent MYNODE !</anynode>’)

4. In palabre.conf edit the [modules] section and add your module name to the list :

[modules]
list = helloworld,yourModule

Restart Palabre … and You’re done !

Accessing Server Variable from a Module

You can access all the methods and properties of the server via :

self.server.XXX

Example: to find out if a particular nickname exists, you would look at the sever variable that holds the list of all nicknames:

self.server.allNickNames

so your test might look like :

if self.server.allNickNames.has_key(node["attrs"]["nickName"]):
    client.clientSendMessage("blabla")

You can also access to a client object via :

self.server.allNickNames[ClientNickName]

And to a room object via :

self.server.allRooms[RoomName]

And then access to all the methods and properties of each object, for example :

self.server.allNickNames[clientNickName].clientSendErrorMessage("Canno t ask for nickName and Room in same request")

or

self.server.allRooms[RoomName].removeRoom()

Included Modules


helloworld.py

[view source]

It adds two nodes "hello" and "quote"
If you send "<hello/>" it will reply "<world>Hello World</world>" …
If you send "<quote>" it will reply with a random quote "<quote>Balblablabla</quote>"
Very simple plugin but shows you how to add actions and nodes easyly with Palabre

dbQueries.py

[view source]

WARNING ! Don’t use this one on production environments !
IF database access is configured in palabre.conf, it allows you to send ANY sql query in a <db/> node !
example : <db>SELECT * FROM my_table</db>
(WARNING, request could be DROP DATABASE ….)
And it will reply :

<dbres >
    <row>
        <field_1>Value</field_1>
            <field_2>Value</field_2>
    </row>
    <row>
        <field_1>Value</field_1>
            <field_2>Value</field_2>
    </row>
</dbres>



You can send "SHOW TABLES" or "SHOW COLUMNS my_table" and it will work too …

simpleLogin.py

[view source]

Just a plugin to explain how to write your own login module
This one is pretty easy .. just don’t send "hacker" as password and you’re in.

Cross Domain Support


Crossdomain support, will really help clarify the way you authorize SWF files to connect the server.

In palabre.conf, in the [crossdomain] section, on the line :

alloweddomains = domainthatdoesnotexist.bar otherinexistantdomain.foo

just specify the domains were people will access your SWFs from

Example:

If you have an swf on http://www.domain.com/test.swf
that can also be accessed through http://www.domain.net/test.swf ,
or http://192.168.0.1/test.swf

specify :

alloweddomains = domain.com domain.net 192.168.0.1

And in your test.fla(swf), execute before the connection to www.domain.com on port 2468 :

System.security.loadPolicyFile("xmlsocket://www.domain.com:2468");
XMLs ocket.connect("www.domain.com",2468);

And even if the SWF is hosted on www.domain.net/test.swf the connection will work.

Using Palabre from Webpage SWF

  • You have Palabre up and running on your computer (IP : x.x.x.x) on port 2468
  • Port is open and anyone could do a telnet x.x.x.x 2468
  • Your SWF is hosted on yourdomain.com/xyz.swf
  • Your SWF is trying to connect to x.x.x.x on port 2468
  • Your palabre.conf has the line
  •  alloweddomains = yourdomain.com www.yourdomain.com
  • Your SWF calls before connecting :
  • System.security.loadPolicyFile("xmlsocket://x.x.x.x:2468");