安装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/ 就可以让你选择昵称和连接方式进入聊天的界面。
代码解读
目录组织结构
这个演示程序的目录组织结构:
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.
// 当有新用户加入时,初始化的一些订阅信息。
// Send a channel here to unsubscribe.
// 在信道channel中发送退订。
// Send events here to publish them.
// 在这里发送事件
)
// 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 给所有订阅者,并且增加到聊天记录中。
// Remove subscriber from subscriber list.
// 订阅者离开后,从用户列表中删除离开者。
}
}
当一个新的用户加入时,处理下面事情:
- 把最新的聊天记录Copy出来,以便提供给新来的用户。
- 把用户订阅channel加入到聊天者channel清单中。
- 聊天订阅者获得新信息的 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
}
}
}
对聊天室框架代码解读可以看下面这个思维导图:
参考资料:
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