Tuesday 28 December, 2010

Multiuser Chatroom with App Engine Channel API



UPDATE
Have a look at part 2 of the series, with focus on optimization.

Perhaps the most primitive use of Google App Engine Channel API is the use of chat between two people in real time. This concept can be extended to chatrooms - where many people chat simultaneously with each other, or gamerooms - where many people play some game simultaneously in real time amongst each other.


The docs don't say much about the quota details of Channel API, so here it is

Free Quota
Channel API Calls 46,310,400
Channels Created 8,640
Channel Data Sent 1,046.00 GBytes

Paid Quota
Channel API Calls 91,995,495
Channels Created 95,040
Channel Data Sent 2,088.13 GBytes

The example application tic-tac-toe shows to a quite good level how to use Channel API for playing duo-player game. I find some scope for improvements in that app. Let's review them :
  1. Everytime a player starts a new game, a new client id (for channel) is created. The cap provided on Channels Creates is few, so this should be used judiciously
  2. The game room generates depends on the User. So, if the user who initiated the play reloads the page, the game is gone. This works for the case of tic-tac-toe but does not go for chatrooms or gamerooms

Apart from above issues, there are somethings that a serious gameroom/ chatroom needs and they are as follows:
  1. Automatic room creation. The room is automatically created as soon as number of players exceed the MAX_PLAYERS limit
  2. Every player has some assets (in a gameroom), and this keeps on changing with actions performed. So there needs to be state persistent information stored at the backend
  3. If the player reloads the page or opens a couple of new tabs, consistency of information should be maintained.
  4. Usually in a chat, when someone joins late, they want to be updated of the chats that took place when they were not there
.

Using above points as my guiding light, I tried to create an app which does the above in a net and beautiful manner. The app's source code is located at http://code.google.com/p/pranav/source/browse/chat-channel.

Structure


The concept of the gameroom/chatroom goes like this - When a player wants to play a game, he is taken to a room. The room could be a new room (if no room exists or all others are full), or an existing room.
There are two entity kinds - Game and PlayerGame. The Game Entity Kind contains information about the game room. This is where you can keep a track of all the events happening in a room like maybe chat between users, or collaborative drawing or the moves in a tic-tac-toe. The PlayerGame is a child entity of the Game entity, which contains the information about the game the user is playing. For those games which go in a sequential manner where player1 does something and then player2 does something, PlayerGame could have very well been inside the Game entity, but in a game where many players can do multiple actions and their actions affect their state in some way or the other datastore congestion might occur. To avoid all those, its made in a separate entity.



Then we need two wrapper Classes so that we can abstract the functioning. Our classes can very well be Player and Tournament.



The Player class contains all the wrapper functions that a player can possible do inside a chatroom/gameroom. Similarly, there shall be a Tournament class which will do all the activities that can be done in a tournament

Flow

Whenever a user comes to the app, first of all it is checked if he was in an existing room or not. If found, then his activities are continued from that stage. If not found then the user is taken to a room. The room could be a new room, if all others are full, or no room is present. The user can perform activities in that room. Filling of rooms goes in First Come, First Serve order. So, when the next user wishes to join a room, the latest room created is checked for vacancy and the user is dropped there. The user is then free to perform actions and have fun. What is typically important here is that, initially a Channel is created between the client and the server, and then using that same channel all the future communication for rooms goes. One advantage of this is that we don't need to create a lot of channels for every user. For this it is very important that the algo which is used to create channel client id has only one variable as userid. (What will happen if we have two variables like userID and timestamp to create the channel client id?).

After the channel is created, the client send requests to join the room. This is taken care by the server and accordingly the user is dropped into a new room or an existing room



This is in a nutshell, a proof of concept about building huge chat-rooms/ game-rooms using Channel API of Google App Engine.

Resources

Read more about optimizing this code in part 2 of the series.
  1. Source Code: http://code.google.com/p/pranav/source/browse/chat-channel
  2. Channel API: http://code.google.com/appengine/docs/python/channel
  3. Discuss: Google Groups Discussion
  4. Tic Tac Toe App: http://code.google.com/p/channel-tac-toe

There are many more things that needs to be taken care of to increase speed and performance, but that shall come in another blog post

4 comments:

  1. Nice post, thanks. It helped me get started with writing a real-time chat on my app engine game.

    A problem with your current approach is that sending messages to 30+ users in one go takes several seconds, and the delay just keeps increasing with more users. At one point my game was taking 15-20 seconds just to send a single message.

    I've managed to have it scale to 300+ concurrent users by making extensive use of the task queue and memcache, although it does use quite an amount of resources and server instances.

    However, it looks like I may have a problem with reaching the channel creation limit. 90,000 seems pretty low compared to the other quota limits... Any help on this? Would I need to create a token per player, and then reuse that token on different pages?

    If you're interested in checking out my chat, my game is here: http://www.boringrpg.com

    ReplyDelete
  2. The approach mentioned in this post is not very optimized one. I have done few modifications in the code so that it works heavily on memcache. The changes can be found in the source code. I am still working on measuring its efficiency and will come up with a post on the new code soon. I'm glad you found it useful.

    ReplyDelete
  3. great post pranav, helped me understand how channnel API works

    ReplyDelete
  4. Thanks, Part 2 of the series about optimization is here http://blog.myblive.com/2011/01/multiuser-chatroom-with-app-engine.html

    ReplyDelete