Diving into APE modules and the JSF – creating topics for channels

So today we’re going to give the ability of giving a channel a topic, much like IRC and in the process learn more about the internals of APE. This requires us to modify the libape-chat.c code and create some additions in the chat.js of the Chat Demo. We’re not going to end up with complete code but you’ll see how flexible APE is and how quickly we can extend it.

First, lets take a look at the Chat Demo source. If you take a quick look you’ll probably notice we don’t explictilty tell APE to join a channel, the JSF takes care of this for us. As we want to specify a topic when we create a channel we’ll need to override the JOIN raw. Let’s take a look at the chat.js code:

We can see on the initialize: function() that we call this.start() which in turn calls this.core.start(). We can see this.core is the APE object we passed when initializing the class. Let’s take a look what happens when we call this.core.start(). Have a peak at APE_JSF\Source\Core\Core.js and do a search for start: you should see it calling this.connect()

        connect: function(options){
                options = this.parseParam(options);
                options.push(this.options.transport);
                this.request('CONNECT', options, false);
        },

We can see the JSF sends APE the CONNECT request and in-turn the server will send a LOGIN raw. We can see this by looking in libape-chat.c:

        register_cmd("CONNECT", 2, jchat_connect, NEED_NOTHING, g_ape);
        static unsigned int chat_connect(callbackp *callbacki)
        {
                /* code removed to shorten block */
                newraw = forge_raw(RAW_LOGIN, jstr); /* pay attention */
                newraw->priority = 1; /* pay attention */
                post_raw(newraw, nuser, callbacki->g_ape); /* pay attention */

                return (FOR_LOGIN | FOR_UPDATE_IP);
        }

So we are sending a LOGIN raw to the client. Back in Core.js we find

        this.onRaw('login', this.rawLogin);
        rawLogin: function(param){
                this.setSessid(param.datas.sessid);
                if (this.options.channel) {
                        this.join(this.options.channel);
                }
                this.status = 1;
                this.fireEvent('init');
                this.startPooler();
        },

Ah-ha! This is were we actually join the channel we specified in client.load():

        join: function(channel){
                this.request('JOIN', channel);
        },

So to create a channel you would essentially call this.core.request(‘JOIN’, {channel, topic}); within your script. But wait, how would the server know how to handle this? It wouldn’t. We need to modify the callback for the JOIN raw, we can put this code in our libape-chat.c.

        register_cmd("JOIN", -1, chat_join, NEED_SESSID, g_ape);

Now let’s create chat_join. It is a copy of the original cmd_join command with three changes (commented):

        unsigned int cmd_join(callbackp *callbacki)
        {
                CHANNEL *jchan;
                RAW *newraw;
                json *jlist;
                BANNED *blist;
                char *topic; /* new */

                if ((jchan = getchan(callbacki->param[2], callbacki->g_ape)) == NULL) {
                        topic = (callbacki->nParam == 3) ? callbacki->param[3] : "Default%20Topic"; /* new */
                        jchan = mkchan(callbacki->param[2], topic /* new */, callbacki->g_ape);

                        if (jchan == NULL) {
                                send_error(callbacki->call_user, "CANT_JOIN_CHANNEL", "202", callbacki->g_ape);

                        } else {
                                join(callbacki->call_user, jchan, callbacki->g_ape);
                        }
                } else if (isonchannel(callbacki->call_user, jchan)) {
                        send_error(callbacki->call_user, "ALREADY_ON_CHANNEL", "100", callbacki->g_ape);
                } else {
                        blist = getban(jchan, callbacki->call_user->ip);
                        if (blist != NULL) {
                                jlist = NULL;

                                set_json("reason", blist->reason, &jlist);
                                set_json("error", "YOU_ARE_BANNED", &jlist);
                                /*
                                        TODO: Add Until
                                */
                                newraw = forge_raw(RAW_ERR, jlist);

                                post_raw(newraw, callbacki->call_user, callbacki->g_ape);
                        } else {
                                join(callbacki->call_user, jchan, callbacki->g_ape);
                        }
                }
                return (FOR_NOTHING);
        }

topic = (callbacki->nParam == 3) ? callbacki->param[3] : “Default%20Topic”; basically checks how many parameters are passed to the function, if it is three then use the third as the topic. Else set a default topic of “Default Topic”.

That’s it, your ready to role. Remove the channel option from client.load otherwise you will create a channel with the default topic. Join progmatically with this.core.request(‘JOIN’, {channel, topic});. For example you could print out a list of available channels using the new CLIST raw (make sure you have the latest git release) and give the user the option to create their own chat. When the user submits the create chat form you would call

        self.core.request('JOIN', {name: encodeURIComponent(channel), topic: encodeURIComponent(topic)});

If you’re interested on how to use the new CLIST raw check out my chat demo and view the source. I would mentioned when returning a list of channels, the data doesn’t contain the channels topic. We can fix this by adding the line:

        set_json("topic", chan->topic, &jprop);

to (in file src/channel.c)

        struct json *get_json_object_channel(CHANNEL *chan){}

right under (towards the bottom)

        set_json("name", chan->name, &jprop);

Enjoy :)

  • Share/Bookmark

Related posts:

  1. Using jQuery with APE – an OOP approach with the DUI
  2. Using jQuery With APE
  3. EsenAPE – send and receive SMS in real time using APE, jQuery, PHP and libape_controller
  4. Using jQuery With APE – change the background-color with PHP
  5. APE – An Introduction

4 Responses to “Diving into APE modules and the JSF – creating topics for channels”

  1. MaRKTD  on July 4th, 2009

    multiple channel don’t work )

    Reply

    • Paul Price  on July 7th, 2009

      How do you mean? The demo above works fine for multiple channels (use two different browsers).

      Reply

  2. Jim Pruetting  on August 15th, 2009

    I am interested in building a site that would use APE to do a real-time news feed and also allow IM-style chats on the same page. Do you know if that is that possible or can an APE user only subscribe to one channel at a time?

    Reply

    • Paul Price  on August 20th, 2009

      Hi Jim, yes you can do this no problem. You just change the ‘channel’ under client.load().

      Reply


Leave a Reply