This commit is contained in:
Liang Ding 2014-09-15 23:20:01 +08:00
parent 24c75e8125
commit a4ce0583b7
5 changed files with 106 additions and 35 deletions

View File

@ -44,7 +44,6 @@ var rawWide conf
func CheckEnv() { func CheckEnv() {
go func() { go func() {
for { for {
if "" == os.Getenv("GOPATH") { if "" == os.Getenv("GOPATH") {
glog.Fatal("Not found $GOPATH") glog.Fatal("Not found $GOPATH")
os.Exit(-1) os.Exit(-1)
@ -60,7 +59,7 @@ func CheckEnv() {
cmd := exec.Command(gocode, "close") cmd := exec.Command(gocode, "close")
_, err := cmd.Output() _, err := cmd.Output()
if nil != err { if nil != err {
event.EventQueue <- event.EvtGocodeNotFount event.EventQueue <- event.EvtCodeGocodeNotFound
glog.Warningf("Not found gocode [%s]", gocode) glog.Warningf("Not found gocode [%s]", gocode)
} }
@ -68,11 +67,12 @@ func CheckEnv() {
cmd = exec.Command(ide_stub, "version") cmd = exec.Command(ide_stub, "version")
_, err = cmd.Output() _, err = cmd.Output()
if nil != err { if nil != err {
event.EventQueue <- event.EvtIDEStubNotFound event.EventQueue <- event.EvtCodeIDEStubNotFound
glog.Warningf("Not found ide_stub [%s]", ide_stub) glog.Warningf("Not found ide_stub [%s]", ide_stub)
} }
time.Sleep(time.Second * 2) // 7 分钟进行一次检查
time.Sleep(time.Minute * 7)
} }
}() }()
} }

View File

@ -4,23 +4,31 @@ package event
import "github.com/golang/glog" import "github.com/golang/glog"
const ( const (
EvtGOPATHNotFound = iota // 事件:找不到环境变量 $GOPATH EvtCodeGOPATHNotFound = iota // 事件代码:找不到环境变量 $GOPATH
EvtGOROOTNotFound // 事件:找不到环境变量 $GOROOT EvtCodeGOROOTNotFound // 事件代码:找不到环境变量 $GOROOT
EvtGocodeNotFount // 事件:找不到 gocode EvtCodeGocodeNotFound // 事件代码:找不到 gocode
EvtIDEStubNotFound // 事件:找不到 IDE stub EvtCodeIDEStubNotFound // 事件代码:找不到 IDE stub
) )
// 事件队列最大长度.
const MaxQueueLength = 10 const MaxQueueLength = 10
// 事件结构.
type Event struct {
Code int `json:"code"` // 事件代码
Sid string `json:"sid"` // 用户会话 id
}
// 全局事件队列. // 全局事件队列.
// 入队的事件将分发到每个用户的通知队列. // 入队的事件将分发到每个用户的通知队列.
var EventQueue = make(chan int, MaxQueueLength) var EventQueue = make(chan int, MaxQueueLength)
// 用户事件队列. // 用户事件队列.
// 入队的事件将翻译为通知,并通过通知通道推送到前端.
var UserEventQueues = map[string]chan int{} var UserEventQueues = map[string]chan int{}
// 用户事件处理器集.
var UserEventHandlers = map[string]*Handlers{}
// 加载事件处理. // 加载事件处理.
func Load() { func Load() {
go func() { go func() {
@ -35,21 +43,51 @@ func Load() {
}() }()
} }
// 添加一个用户事件队列. // 初始化一个用户事件队列.
func InitUserQueue(sid string) { func InitUserQueue(sid string, handlers ...Handler) {
// FIXME: 会话过期后需要销毁对应的用户事件队列 // FIXME: 会话过期后需要销毁对应的用户事件队列
q := UserEventQueues[sid] q := UserEventQueues[sid]
if nil != q { if nil != q {
close(q) return
} }
q = make(chan int, MaxQueueLength) q = make(chan int, MaxQueueLength)
UserEventQueues[sid] = q UserEventQueues[sid] = q
if nil == UserEventHandlers[sid] {
UserEventHandlers[sid] = new(Handlers)
}
for _, handler := range handlers {
UserEventHandlers[sid].add(handler)
}
go func() { go func() {
for event := range q { for evtCode := range q {
glog.Infof("Session [%s] received a event [%d]", sid, event) glog.V(5).Infof("Session [%s] received a event [%d]", sid, evtCode)
// 将事件交给事件处理器进行处理
for _, handler := range *UserEventHandlers[sid] {
e := Event{Code: evtCode, Sid: sid}
handler.Handle(&e)
}
} }
}() }()
} }
type Handler interface {
Handle(event *Event)
}
type HandleFunc func(event *Event)
func (fn HandleFunc) Handle(event *Event) {
fn(event)
}
type Handlers []Handler
func (handlers *Handlers) add(handler Handler) {
*handlers = append(*handlers, handler)
}

View File

@ -272,7 +272,7 @@ func listFiles(dirname string) []string {
func getIconSkin(filenameExtension string) string { func getIconSkin(filenameExtension string) string {
switch filenameExtension { switch filenameExtension {
case ".gitignore", "", ".exe", ".s": case ".gitignore", "", ".exe", ".s", ".tar", ".zip", ".rar", ".gz": // 不支持显示图标的文件
return "ico-ztree-other " return "ico-ztree-other "
case ".json", ".js": case ".json", ".js":
return "ico-ztree-js " return "ico-ztree-js "

View File

@ -21,5 +21,7 @@
"goget": "go get", "goget": "go get",
"goinstall": "go install", "goinstall": "go install",
"build_n_run": "构建 & 运行", "build_n_run": "构建 & 运行",
"full_screen": "全屏" "full_screen": "全屏",
"notification_2": "没有检查到 gocode这将会导致 [自动完成] 失效",
"notification_3": "没有检查到 ide_stub这将会导致 [跳转到声明]、[查找使用] 失效"
} }

View File

@ -8,52 +8,83 @@ import (
"runtime" "runtime"
"time" "time"
"strconv"
"github.com/b3log/wide/conf" "github.com/b3log/wide/conf"
"github.com/b3log/wide/event" "github.com/b3log/wide/event"
"github.com/b3log/wide/i18n"
"github.com/b3log/wide/user" "github.com/b3log/wide/user"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
const (
Error = "ERROR" // 通知.严重程度ERROR
Warn = "WARN" // 通知.严重程度WARN
Info = "INFO" // 通知.严重程度INFO
Setup = "Setup" // 通知.类型:安装
)
// 通知结构. // 通知结构.
type Notification struct { type Notification struct {
Event int event *event.Event
Type string Type string `json:"type"`
Severity string // ERROR/WARN/INFO Severity string `json:"severity"`
Message string Message string `json:"message"`
} }
// 一个用户会话的 WebSocket 通道结构. // 一个用户会话的 WebSocket 通道结构.
type WSChannel struct { type WSChannel struct {
Conn *websocket.Conn // WebSocket 连接 Conn *websocket.Conn // WebSocket 连接
Time time.Time // 该通道最近一次使用时间 Request *http.Request // 关联的 HTTP 请求
Time time.Time // 该通道最近一次使用时间
} }
// 通知通道. // 通知通道.
// <username, {<sid1, WSChannel1>, <sid2, WSChannel2>}> // <sid, WSChannel>
var notificationWSs = map[string]map[string]WSChannel{} var notificationWSs = map[string]*WSChannel{}
func event2Notification(e *event.Event) {
if nil == notificationWSs[e.Sid] {
return
}
wsChannel := notificationWSs[e.Sid]
var notification Notification
switch e.Code {
case event.EvtCodeGocodeNotFound:
notification = Notification{event: e, Type: Setup, Severity: Error}
case event.EvtCodeIDEStubNotFound:
notification = Notification{event: e, Type: Setup, Severity: Error}
default:
glog.Warningf("Can't handle event[code=%d]", e.Code)
return
}
msgs := i18n.GetLangs(wsChannel.Request)
notification.Message = msgs["notification_"+strconv.Itoa(e.Code)].(string)
wsChannel.Conn.WriteJSON(&notification)
}
func WSHandler(w http.ResponseWriter, r *http.Request) { func WSHandler(w http.ResponseWriter, r *http.Request) {
session, _ := user.Session.Get(r, "wide-session") session, _ := user.Session.Get(r, "wide-session")
username := session.Values["username"].(string)
sid := session.Values["id"].(string) sid := session.Values["id"].(string)
conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024) conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
wsChan := WSChannel{Conn: conn, Time: time.Now()} wsChan := WSChannel{Conn: conn, Request: r, Time: time.Now()}
wsChans := notificationWSs[username] notificationWSs[sid] = &wsChan
if nil == wsChans {
wsChans = map[string]WSChannel{}
}
wsChans[sid] = wsChan
ret := map[string]interface{}{"output": "Notification initialized", "cmd": "init-notification"} ret := map[string]interface{}{"output": "Notification initialized", "cmd": "init-notification"}
wsChan.Conn.WriteJSON(&ret) wsChan.Conn.WriteJSON(&ret)
glog.Infof("Open a new [Notification] with session [%s], %d", sid, len(wsChans)) glog.Infof("Open a new [Notification] with session [%s], %d", sid, len(notificationWSs))
event.InitUserQueue(sid) // 初始化用户事件队列
event.InitUserQueue(sid, event.HandleFunc(event2Notification))
input := map[string]interface{}{} input := map[string]interface{}{}