Saturday, May 16, 2009

Create a chat client and server with Flex and Python

In this example we'll create a simple Flex chat client that uses Producer/Consumer messaging to send and receive messages through a Python server. The server will use AmFast's HTTP polling and long-polling channels. Get the complete example code here.

First let's setup the Producer and Consumer in Actionscript.

// Configure the ChannelSet that
// messages will be sent and received over.
import mx.messaging.ChannelSet;
import mx.messaging.channels.AMFChannel;
var channelSet:ChannelSet = new ChannelSet();
var channel:AMFChannel = new AMFChannel("channel-name", "server-url");
channelSet.addChannel(channel);

// Setup a Consumer to receive messages.
import mx.messaging.Consumer;
var consumer:Consumer = new Consumer();

// The consumer's destination is the 'topic'
// name that the consumer will be subscribed to.
// The consumer will receive all messages
// published to the topic.
consumer.destination = "topic";

// Use the ChannelSet that was already created.
consumer.channelSet = channelSet;

// This event listener will be called whenever
// the consumer receives a message from the server.
consumer.addEventListener(MessageEvent.MESSAGE, newMsgHandler);

// The consumer won't start receiving messages
// until it is subscribed.
consumer.subscribe();

// Setup a Producer to publish messages.
import mx.messaging.Producer;
var producer:Producer = new Producer();
producer.destination = "topic";
producer.channelSet = channelSet;

// Create an Async message and send it
// to all other clients subscribed to the topic.
import mx.messaging.messages.AsyncMessage;
var msg:AsyncMessage = new AsynMessage();

// Set the message's body attribute to the
// object that is going to be published.
//
// In this case the object is a String,
// but the message body can be any
// type of object.
msg.body = "This is being published!";
producer.send(msg);



Next we'll setup the server.

# Create a ChannelSet to serve messages.
from amfast.remoting.channel import ChannelSet
from amfast.remoting.wsgi_channel import WsgiChannel
channel_set = ChannelSet()

# Each individual ChannelSet can use
# one or more Channels. When messages
# are published through the ChannelSet,
# they will be published to all subscribed clients,
# regardless of which Channel the clients
# are connected through.

# Create s standard polling channel.
polling_channel = WsgiChannel('poll-channel')

# A long-polling channel is created similar
# to a normal channel, but the wait_interval
# argument must be set to -1.
long_channel = WsgiChannel('long-channel', wait_interval=-1)

# WsgiChannels objects are wsgi applications
# that can be served with any Wsgi server.
# CherryPy is being used in this example.
cherrypy.tree.graft(polling_channel, '/amf')
cherrypy.tree.graft(long_channel, '/longPoll')

# Start the server.
# App() is your root controller class
# for non-AMF functions.
cherrypy.quickstart(App(), '/')

# That's it, our server is up and running.
# It's that simple.


To test the example, download the full code from the repo. To run the example you'll need to install AmFast and CherryPy or Twisted 1st.


# To server the example with cherrypy
python cp_server.py

# To server the example with Twisted
twistd -noy twisted_server.tac


Open two browser windows and browse to 'http://localhost:8000'. In the 1st window set the messaging url to 'http://localhost:8000/amf' to use the polling channel. In the 2nd window set the messaging url to 'http://localhost:8000/longPoll' to use the long-polling channel. Click the 'Subscribe' button in both windows. Enter a message in the message entry box, and press the 'Publish' button to publish the message. The published message will appear in both clients.

9 comments:

  1. Thank you for such good example.

    What if: clietn send request to server, server respond to this client immediately, AND after 2-3 seconds server need to push to client another message. can you please elaborate on this with Twisted+FLEX example?

    ReplyDelete
  2. The message will be delivered to the client the next time the client polls the server.

    ReplyDelete
  3. Is it possible to publish the data from server to client/s and not from client to client, as in original topic, using Twisted?

    ReplyDelete
  4. Yes

    On the server side, you can use the method ChannelSet.publishMessage() or ChannelSet.publishObject()to publish a message to clients.

    See the documentation here for more details:
    http://code.google.com/p/amfast/wiki/MessagingServer#Producer/Consumer_Messaging

    ReplyDelete
  5. What should be done on FLEX in order to make your example work with SSL? Thank you.

    ReplyDelete
  6. Setup your server to serve with SSL, and change your client channel to point to the secure URL, for example: 'https://localhost:443/amf' instead of 'http://localhost:8000/amf'.

    ReplyDelete
  7. In the addition to what you said I was need to change on FLEX side AMFChannel to SecureAMFChannel and now I see in tcpdump encrypted content.

    ReplyDelete
  8. Does amfast remoting.Service() is the same logical gateway as pyamf remoting.TwistedGateway()?

    Is there any mailing list for Q&A except http://groups.google.com/group/amfast ?

    Thank you.

    ReplyDelete
  9. Yes, you must also use SecureAMFChannel, forgot about that :)

    remoting.Service objects are collections of remoting.Target objects.

    The Flex client object RemoteObject maps to a specific remoting.Service on the server side (specified in RemoteObject.destination). remoting.Target objects execute functions invoked remotely by RemoteObject or NetConnection.

    The remoting.channel.Channel class is the closest equivalent to a pyamf Gateway.

    http://groups.google.com/group/amfast is the official mailing list.

    ReplyDelete