导航

Go语言Revel框架 的聊天室示例解读

Posted on 2013-04-03 09:22  蝈蝈俊  阅读(1092)  评论(0编辑  收藏  举报

安装Revel框架请参看下面这篇文章:《Go语言Revel框架 准备工作》 http://www.cnblogs.com/ghj1976/archive/2013/03/24/2979709.html

运行聊天室例子

运行聊天室例子只需执行下面命令:

$ revel run github.com/robfig/revel/samples/chat

$ revel run github.com/robfig/revel/samples/chat
~
~ revel! http://robfig.github.com/revel
~
2013/03/25 11:54:42 revel.go:240: Loaded module static
2013/03/25 11:54:42 run.go:57: Running chat (github.com/robfig/revel/samples/chat) in dev mode
2013/03/25 11:54:42 harness.go:143: Listening on :9000
2013/03/25 11:54:55 revel.go:240: Loaded module static
2013/03/25 11:54:55 main.go:26: Running revel server
2013/03/25 11:54:55 i18n.go:93: Error reading messages files: lstat /Users/cybercare/go/src/github.com/robfig/revel/samples/chat/messages: no such file or directory
Listening on port 52482...

这时候访问 http://localhost:9000/ 就可以让你选择昵称和连接方式进入聊天的界面。

NewImage

代码解读

目录组织结构

这个演示程序的目录组织结构:

Here are the contents of the app:

chat/app/
chatroom # Chat room routines 聊天室协程
chatroom.go
controllers
app.go # The welcome screen, allowing user to pick a technology 欢迎页面,允许客户选择一个数据
refresh.go # Handlers for the "Active Refresh" chat demo 定时刷新的聊天室Demo
longpolling.go # Handlers for the "Long polling" ("Comet") chat demo 长连接 Comet技术的聊天室
websocket.go # Handlers for the "Websocket" chat demo Websocket 技术的聊天室
views
... # HTML and Javascript

解读 chatroom.go 

一个聊天室开一个协程来单独处理,chatroom() 函数无限循环运行,处理每次聊天的请求。

func init() {

     go chatroom()

}

 

chatroom() 函数 在三个 channels 之间 select, 并执行相应的请求操作。

type Event struct {

    Type      string // "join", "leave", or "message" 演示Demo只有这三种类型

    User      string // 发出事件的用户名

    Timestamp int    // Unix timestmap (secs) 发出事件的系统时间

    Text      string // What the user said (if Type == "message")  用户说的内容,只有 Type=message时,才会有这个信息。

}

 

type Subscription struct {

    Archive []Event      // All the events from the archive.  归档的所有事件

    New     <-chan Event // New events coming in.  新到来的事件

}


var (

    // Send a channel here to get room events back.  It will send the entire

    // archive initially, and then new messages as they come in.

    // 当有新用户加入时,初始化的一些订阅信息。

    subscribe = make(chan (chan<- Subscription), 10)


    // Send a channel here to unsubscribe.

    // 在信道channel中发送退订。

    unsubscribe = make(chan (<-chan Event), 10)


    // Send events here to publish them.

    // 在这里发送事件

    publish = make(chan Event, 10)

)

 

// This function loops forever, handling the chat room pubsub

func chatroom() {

    archive := list.New()      // 最近的几条聊天记录

    subscribers := list.New()  // 订阅者列表

 

    for {

        select {

        case ch := <-subscribe:

            // Add subscriber to list and send back subscriber channel + chat log.

            // 当有新用户加入聊天时,添加到用户列表并给该用户发送 channel 和聊天记录。

        case event := <-publish:

            // Send event to all subscribers and add to chat log.

            // 发送 Event 给所有订阅者,并且增加到聊天记录中。

        case unsub :=<-unsubscribe:

            // Remove subscriber from subscriber list.

            // 订阅者离开后,从用户列表中删除离开者。

        }

    }

}

 

当一个新的用户加入时,处理下面事情:

  1. 把最新的聊天记录Copy出来,以便提供给新来的用户。
  2. 把用户订阅channel加入到聊天者channel清单中。
  3. 聊天订阅者获得新信息的 channel 

       case ch := <-subscribe:

 

            var events []Event

            for e := archive.Front(); e != nil; e = e.Next() {

                events = append(events, e.Value.(Event))

            }

            subscriber := make(chan Event, 10)

            subscribers.PushBack(subscriber)

            ch <- Subscription{events, subscriber}

 

当用户发布新聊天内容时,发布的event一个一个发送给订阅者的channel,然后event被添加到archive,archive里面的数量大于10,前面的会被移出。

 

       case event := <-publish:

 

            for ch := subscribers.Front(); ch != nil; ch = ch.Next() {

                ch.Value.(chan Event) <- event

            }

            if archive.Len() >= archiveSize {

                archive.Remove(archive.Front())

            }

            archive.PushBack(event)

 

当有用户离开聊天室时,订阅者channel在list中被移除。

       case unsub := <-unsubscribe:

 

            for ch := subscribers.Front(); ch != nil; ch = ch.Next() {

                if ch.Value.(chan Event) == unsub {

                    subscribers.Remove(ch)

                    break

                }

            }

        }

对聊天室框架代码解读可以看下面这个思维导图:

NewImage

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考资料:

http://robfig.github.com/revel/index.html

http://robfig.github.com/revel/samples/chat.html 

http://robfig.github.com/revel/samples/index.html

Revel示例 - 聊天室
http://www.cnblogs.com/ztiandan/archive/2013/01/23/2864872.html

 

http://bbs.studygolang.com/thread-291-1-1.html