This commit is contained in:
Liang Ding 2014-10-29 00:04:46 +08:00
parent 6e5d13cf2f
commit 190f30c9f4
8 changed files with 69 additions and 42 deletions

View File

@ -75,11 +75,13 @@ func FixedTimeCheckEnv() {
for _ = range time.Tick(time.Minute * 7) { for _ = range time.Tick(time.Minute * 7) {
if "" == os.Getenv("GOPATH") { if "" == os.Getenv("GOPATH") {
glog.Fatal("Not found $GOPATH") glog.Fatal("Not found $GOPATH")
os.Exit(-1) os.Exit(-1)
} }
if "" == os.Getenv("GOROOT") { if "" == os.Getenv("GOROOT") {
glog.Fatal("Not found $GOROOT") glog.Fatal("Not found $GOROOT")
os.Exit(-1) os.Exit(-1)
} }
@ -87,7 +89,8 @@ func FixedTimeCheckEnv() {
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.EvtCodeGocodeNotFound event.EventQueue <- &event.Event{Code: event.EvtCodeGocodeNotFound}
glog.Warningf("Not found gocode [%s]", gocode) glog.Warningf("Not found gocode [%s]", gocode)
} }
@ -95,7 +98,8 @@ func FixedTimeCheckEnv() {
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.EvtCodeIDEStubNotFound event.EventQueue <- &event.Event{Code: event.EvtCodeIDEStubNotFound}
glog.Warningf("Not found ide_stub [%s]", ide_stub) glog.Warningf("Not found ide_stub [%s]", ide_stub)
} }
} }

View File

@ -8,6 +8,7 @@ const (
EvtCodeGOROOTNotFound // 事件代码:找不到环境变量 $GOROOT EvtCodeGOROOTNotFound // 事件代码:找不到环境变量 $GOROOT
EvtCodeGocodeNotFound // 事件代码:找不到 gocode EvtCodeGocodeNotFound // 事件代码:找不到 gocode
EvtCodeIDEStubNotFound // 事件代码:找不到 IDE stub EvtCodeIDEStubNotFound // 事件代码:找不到 IDE stub
EvtCodeServerInternalError // 事件代码:服务器内部错误
) )
// 事件队列最大长度. // 事件队列最大长度.
@ -17,17 +18,18 @@ const MaxQueueLength = 10
type Event struct { type Event struct {
Code int `json:"code"` // 事件代码 Code int `json:"code"` // 事件代码
Sid string `json:"sid"` // 用户会话 id Sid string `json:"sid"` // 用户会话 id
Data interface{} `json:"data"` // 事件数据
} }
// 全局事件队列. // 全局事件队列.
// //
// 入队的事件将分发到每个用户的事件队列中. // 入队的事件将分发到每个用户的事件队列中.
var EventQueue = make(chan int, MaxQueueLength) var EventQueue = make(chan *Event, MaxQueueLength)
// 用户事件队列. // 用户事件队列.
type UserEventQueue struct { type UserEventQueue struct {
Sid string // 关联的会话 id Sid string // 关联的会话 id
Queue chan int // 队列 Queue chan *Event // 队列
Handlers []Handler // 事件处理器集 Handlers []Handler // 事件处理器集
} }
@ -43,10 +45,12 @@ var UserEventQueues = Queues{}
func Load() { func Load() {
go func() { go func() {
for event := range EventQueue { for event := range EventQueue {
glog.V(5).Info("收到全局事件 [%d]", event) glog.V(5).Infof("收到全局事件 [%d]", event.Code)
// 将事件分发到每个用户的事件队列里 // 将事件分发到每个用户的事件队列里
for _, userQueue := range UserEventQueues { for _, userQueue := range UserEventQueues {
event.Sid = userQueue.Sid
userQueue.Queue <- event userQueue.Queue <- event
} }
} }
@ -71,19 +75,18 @@ func (ueqs Queues) New(sid string) *UserEventQueue {
q = &UserEventQueue{ q = &UserEventQueue{
Sid: sid, Sid: sid,
Queue: make(chan int, MaxQueueLength), Queue: make(chan *Event, MaxQueueLength),
} }
ueqs[sid] = q ueqs[sid] = q
go func() { // 队列开始监听事件 go func() { // 队列开始监听事件
for evtCode := range q.Queue { for evt := range q.Queue {
glog.V(5).Infof("Session [%s] received a event [%d]", sid, evtCode) glog.V(5).Infof("Session [%s] received a event [%d]", sid, evt.Code)
// 将事件交给事件处理器进行处理 // 将事件交给事件处理器进行处理
for _, handler := range q.Handlers { for _, handler := range q.Handlers {
handler.Handle(&Event{Code: evtCode, Sid: sid}) handler.Handle(evt)
} }
} }
}() }()

View File

@ -1,4 +1,4 @@
// 文件树操作. // File tree manipulations.
package file package file
import ( import (
@ -12,17 +12,18 @@ import (
"strings" "strings"
"github.com/b3log/wide/conf" "github.com/b3log/wide/conf"
"github.com/b3log/wide/event"
"github.com/b3log/wide/session" "github.com/b3log/wide/session"
"github.com/b3log/wide/util" "github.com/b3log/wide/util"
"github.com/golang/glog" "github.com/golang/glog"
) )
// 文件节点,用于构造文件树. // File node, used to construct the file tree.
type FileNode struct { type FileNode struct {
Name string `json:"name"` Name string `json:"name"`
Path string `json:"path"` Path string `json:"path"`
IconSkin string `json:"iconSkin"` // 值的末尾应该有一个空格 IconSkin string `json:"iconSkin"` // Value should be end with a space
Type string `json:"type"` // "f":文件,"d":文件夹 Type string `json:"type"` // "f": file"d": directory
Mode string `json:"mode"` Mode string `json:"mode"`
FileNodes []*FileNode `json:"children"` FileNodes []*FileNode `json:"children"`
} }
@ -175,7 +176,7 @@ func SaveFile(w http.ResponseWriter, r *http.Request) {
} }
} }
// 新建文件/目录. // NewFile handles request of creating file or directory.
func NewFile(w http.ResponseWriter, r *http.Request) { func NewFile(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -191,10 +192,16 @@ func NewFile(w http.ResponseWriter, r *http.Request) {
path := args["path"].(string) path := args["path"].(string)
fileType := args["fileType"].(string) fileType := args["fileType"].(string)
sid := args["sid"].(string)
wSession := session.WideSessions.Get(sid)
if !createFile(path, fileType) { if !createFile(path, fileType) {
data["succ"] = false data["succ"] = false
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
Data: "can't create file " + path}
return return
} }
@ -204,7 +211,7 @@ func NewFile(w http.ResponseWriter, r *http.Request) {
} }
} }
// 删除文件/目录. // RemoveFile handles request of removing file or directory.
func RemoveFile(w http.ResponseWriter, r *http.Request) { func RemoveFile(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -225,7 +232,7 @@ func RemoveFile(w http.ResponseWriter, r *http.Request) {
} }
} }
// 在目录中搜索包含指定字符串的文件. // SearchText handles request of searching files under the specified directory with the specified keyword.
func SearchText(w http.ResponseWriter, r *http.Request) { func SearchText(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)

View File

@ -35,6 +35,7 @@
"unread_notification": "Unread", "unread_notification": "Unread",
"notification_2": "Not found [gocode], thereby [Autocomplete] will not work", "notification_2": "Not found [gocode], thereby [Autocomplete] will not work",
"notification_3": "Not found [ide_stub], thereby [Jump to Decl], [Find Usages] will not work", "notification_3": "Not found [ide_stub], thereby [Jump to Decl], [Find Usages] will not work",
"notification_4": "Server internal error",
"goto_line": "Goto Line", "goto_line": "Goto Line",
"go": "Go", "go": "Go",
"tip": "Tip", "tip": "Tip",

View File

@ -35,6 +35,7 @@
"unread_notification": "未読の通知", "unread_notification": "未読の通知",
"notification_2": "[gocode] が見つかりません。[Autocomplete] は動作しません。", "notification_2": "[gocode] が見つかりません。[Autocomplete] は動作しません。",
"notification_3": "[ide_stub] が見つかりません。[Jump to Decl]、[Find Usages] は動作しません。", "notification_3": "[ide_stub] が見つかりません。[Jump to Decl]、[Find Usages] は動作しません。",
"notification_4": "内部サーバーエラー",
"goto_line": "指定行にジャンプ", "goto_line": "指定行にジャンプ",
"go": "Go", "go": "Go",
"tip": "ヒント", "tip": "ヒント",

View File

@ -35,6 +35,7 @@
"unread_notification": "未读通知", "unread_notification": "未读通知",
"notification_2": "没有检查到 gocode这将会导致 [自动完成] 失效", "notification_2": "没有检查到 gocode这将会导致 [自动完成] 失效",
"notification_3": "没有检查到 ide_stub这将会导致 [跳转到声明]、[查找使用] 失效", "notification_3": "没有检查到 ide_stub这将会导致 [跳转到声明]、[查找使用] 失效",
"notification_4": "服务器内部错误",
"goto_line": "跳转到行", "goto_line": "跳转到行",
"go": "跳转", "go": "跳转",
"tip": "提示", "tip": "提示",

View File

@ -3,7 +3,6 @@ package notification
import ( import (
"net/http" "net/http"
"time" "time"
"strconv" "strconv"
@ -22,6 +21,7 @@ const (
Info = "INFO" // 通知.严重程度INFO Info = "INFO" // 通知.严重程度INFO
Setup = "Setup" // 通知.类型:安装 Setup = "Setup" // 通知.类型:安装
Server = "Server" // 通知.类型:服务器
) )
// 通知结构. // 通知结构.
@ -41,16 +41,7 @@ func event2Notification(e *event.Event) {
} }
wsChannel := session.NotificationWS[e.Sid] wsChannel := session.NotificationWS[e.Sid]
if nil == wsChannel {
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 return
} }
@ -58,13 +49,26 @@ func event2Notification(e *event.Event) {
username := httpSession.Values["username"].(string) username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale locale := conf.Wide.GetUser(username).Locale
// 消息国际化处理 var notification *Notification
notification.Message = i18n.Get(locale, "notification_"+strconv.Itoa(e.Code)).(string)
wsChannel.Conn.WriteJSON(&notification) switch e.Code {
case event.EvtCodeGocodeNotFound:
fallthrough
case event.EvtCodeIDEStubNotFound:
notification = &Notification{event: e, Type: Setup, Severity: Error,
Message: i18n.Get(locale, "notification_"+strconv.Itoa(e.Code)).(string)}
case event.EvtCodeServerInternalError:
notification = &Notification{event: e, Type: Server, Severity: Error,
Message: i18n.Get(locale, "notification_"+strconv.Itoa(e.Code)).(string) + " [" + e.Data.(string) + "]"}
default:
glog.Warningf("Can't handle event[code=%d]", e.Code)
// 更新通道最近使用时间 return
wsChannel.Time = time.Now() }
wsChannel.Conn.WriteJSON(notification)
wsChannel.Refresh()
} }
// 建立通知通道. // 建立通知通道.
@ -101,6 +105,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
} }
glog.Error("Notification WS ERROR: " + err.Error()) glog.Error("Notification WS ERROR: " + err.Error())
return return
} }
} }

View File

@ -19,3 +19,8 @@ type WSChannel struct {
func (c *WSChannel) Close() { func (c *WSChannel) Close() {
c.Conn.Close() c.Conn.Close()
} }
// Refresh refreshes the channel by updating its Time.
func (c *WSChannel) Refresh() {
c.Time = time.Now()
}