commit
d21dc7bc4d
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,11 +82,9 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// 自动完成(代码补全).
|
// 自动完成(代码补全).
|
||||||
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
|
|
||||||
|
@ -167,10 +165,8 @@ func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||||
username := session.Values["username"].(string)
|
username := session.Values["username"].(string)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
|
|
||||||
|
@ -241,10 +237,8 @@ func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||||
username := session.Values["username"].(string)
|
username := session.Values["username"].(string)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
|
|
||||||
|
@ -323,11 +317,9 @@ func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
session, _ := session.HTTPSession.Get(r, "wide-session")
|
session, _ := session.HTTPSession.Get(r, "wide-session")
|
||||||
username := session.Values["username"].(string)
|
username := session.Values["username"].(string)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
|
|
||||||
|
|
|
@ -94,11 +94,9 @@ func HTMLFmtHandler(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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
@ -151,11 +149,9 @@ func JSONFmtHandler(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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,11 @@ package event
|
||||||
import "github.com/golang/glog"
|
import "github.com/golang/glog"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EvtCodeGOPATHNotFound = iota // 事件代码:找不到环境变量 $GOPATH
|
EvtCodeGOPATHNotFound = iota // 事件代码:找不到环境变量 $GOPATH
|
||||||
EvtCodeGOROOTNotFound // 事件代码:找不到环境变量 $GOROOT
|
EvtCodeGOROOTNotFound // 事件代码:找不到环境变量 $GOROOT
|
||||||
EvtCodeGocodeNotFound // 事件代码:找不到 gocode
|
EvtCodeGocodeNotFound // 事件代码:找不到 gocode
|
||||||
EvtCodeIDEStubNotFound // 事件代码:找不到 IDE stub
|
EvtCodeIDEStubNotFound // 事件代码:找不到 IDE stub
|
||||||
|
EvtCodeServerInternalError // 事件代码:服务器内部错误
|
||||||
)
|
)
|
||||||
|
|
||||||
// 事件队列最大长度.
|
// 事件队列最大长度.
|
||||||
|
@ -15,20 +16,21 @@ 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)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
123
file/files.go
123
file/files.go
|
@ -1,4 +1,4 @@
|
||||||
// 文件树操作.
|
// File tree manipulations.
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -12,32 +12,34 @@ 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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 代码片段. 这个结构可用于“查找使用”、“文件搜索”等的返回值.
|
// Source code snippet, used to as the result of "Find Usages", "Search".
|
||||||
type Snippet struct {
|
type Snippet struct {
|
||||||
Path string `json:"path"` // 文件路径
|
Path string `json:"path"` // file path
|
||||||
Line int `json:"line"` // 行号
|
Line int `json:"line"` // line number
|
||||||
Ch int `json:"ch"` // 列号
|
Ch int `json:"ch"` // column number
|
||||||
Contents []string `json:"contents"` // 附近几行
|
Contents []string `json:"contents"` // lines nearby
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造用户工作空间文件树.
|
// GetFiles handles request of constructing user workspace file tree.
|
||||||
//
|
//
|
||||||
// 将 Go API 源码包($GOROOT/src/pkg)也作为子节点,这样能方便用户查看 Go API 源码.
|
// The Go API source code package ($GOROOT/src/pkg) also as a child node,
|
||||||
|
// so that users can easily view the Go API source code.
|
||||||
func GetFiles(w http.ResponseWriter, r *http.Request) {
|
func GetFiles(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)
|
||||||
|
@ -50,7 +52,7 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
root := FileNode{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
|
root := FileNode{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", FileNodes: []*FileNode{}}
|
||||||
|
|
||||||
// 工作空间节点处理
|
// workspace node process
|
||||||
for _, workspace := range workspaces {
|
for _, workspace := range workspaces {
|
||||||
workspacePath := workspace + conf.PathSeparator + "src"
|
workspacePath := workspace + conf.PathSeparator + "src"
|
||||||
|
|
||||||
|
@ -60,45 +62,43 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
walk(workspacePath, &workspaceNode)
|
walk(workspacePath, &workspaceNode)
|
||||||
|
|
||||||
// 添加工作空间节点
|
// add workspace node
|
||||||
root.FileNodes = append(root.FileNodes, &workspaceNode)
|
root.FileNodes = append(root.FileNodes, &workspaceNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造 Go API 节点
|
// construct Go API node
|
||||||
apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg"
|
apiPath := runtime.GOROOT() + conf.PathSeparator + "src" + conf.PathSeparator + "pkg"
|
||||||
apiNode := FileNode{Name: "Go API", Path: apiPath, FileNodes: []*FileNode{}}
|
apiNode := FileNode{Name: "Go API", Path: apiPath, FileNodes: []*FileNode{}}
|
||||||
|
|
||||||
goapiBuildOKSignal := make(chan bool)
|
goapiBuildOKSignal := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
apiNode.Type = "d"
|
apiNode.Type = "d"
|
||||||
// TOOD: Go API 用另外的样式
|
// TOOD: Go API use a special style
|
||||||
apiNode.IconSkin = "ico-ztree-dir "
|
apiNode.IconSkin = "ico-ztree-dir "
|
||||||
|
|
||||||
walk(apiPath, &apiNode)
|
walk(apiPath, &apiNode)
|
||||||
|
|
||||||
// 放行信号
|
// go-ahead
|
||||||
close(goapiBuildOKSignal)
|
close(goapiBuildOKSignal)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 等待放行
|
// waiting
|
||||||
<-goapiBuildOKSignal
|
<-goapiBuildOKSignal
|
||||||
|
|
||||||
// 添加 Go API 节点
|
// add Go API node
|
||||||
root.FileNodes = append(root.FileNodes, &apiNode)
|
root.FileNodes = append(root.FileNodes, &apiNode)
|
||||||
|
|
||||||
data["root"] = root
|
data["root"] = root
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编辑器打开一个文件.
|
// GetFile handles request of opening file by editor.
|
||||||
func GetFile(w http.ResponseWriter, r *http.Request) {
|
func GetFile(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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
@ -110,8 +110,9 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
extension := filepath.Ext(path)
|
extension := filepath.Ext(path)
|
||||||
|
|
||||||
// 通过文件扩展名判断是否是图片文件(图片在浏览器里新建 tab 打开)
|
|
||||||
if isImg(extension) {
|
if isImg(extension) {
|
||||||
|
// image file will be open in a browser tab
|
||||||
|
|
||||||
data["mode"] = "img"
|
data["mode"] = "img"
|
||||||
|
|
||||||
path2 := strings.Replace(path, "\\", "/", -1)
|
path2 := strings.Replace(path, "\\", "/", -1)
|
||||||
|
@ -122,15 +123,14 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
isBinary := false
|
isBinary := false
|
||||||
// 判断是否是其他二进制文件
|
// determine whether it is a binary file
|
||||||
for _, b := range buf {
|
for _, b := range buf {
|
||||||
if 0 == b { // 包含 0 字节就认为是二进制文件
|
if 0 == b {
|
||||||
isBinary = true
|
isBinary = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isBinary {
|
if isBinary {
|
||||||
// 是二进制文件的话前端编辑器不打开
|
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
data["msg"] = "Can't open a binary file :("
|
data["msg"] = "Can't open a binary file :("
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,16 +140,14 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存文件.
|
// SaveFile handles request of saving file.
|
||||||
func SaveFile(w http.ResponseWriter, r *http.Request) {
|
func SaveFile(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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
@ -157,6 +155,7 @@ func SaveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := args["file"].(string)
|
filePath := args["file"].(string)
|
||||||
|
sid := args["sid"].(string)
|
||||||
|
|
||||||
fout, err := os.Create(filePath)
|
fout, err := os.Create(filePath)
|
||||||
|
|
||||||
|
@ -175,20 +174,22 @@ func SaveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
wSession := session.WideSessions.Get(sid)
|
||||||
|
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||||
|
Data: "can't save file " + filePath}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新建文件/目录.
|
// 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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
@ -197,10 +198,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,16 +217,14 @@ 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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
@ -227,13 +232,19 @@ func RemoveFile(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
path := args["path"].(string)
|
path := args["path"].(string)
|
||||||
|
sid := args["sid"].(string)
|
||||||
|
|
||||||
|
wSession := session.WideSessions.Get(sid)
|
||||||
|
|
||||||
if !removeFile(path) {
|
if !removeFile(path) {
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
wSession.EventQueue.Queue <- &event.Event{Code: event.EvtCodeServerInternalError, Sid: sid,
|
||||||
|
Data: "can't remove file " + path}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在目录中搜索包含指定字符串的文件.
|
// 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)
|
||||||
|
@ -256,7 +267,7 @@ func SearchText(w http.ResponseWriter, r *http.Request) {
|
||||||
data["founds"] = founds
|
data["founds"] = founds
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历指定的路径,构造文件树.
|
// walk traverses the specified path to build a file tree.
|
||||||
func walk(path string, node *FileNode) {
|
func walk(path string, node *FileNode) {
|
||||||
files := listFiles(path)
|
files := listFiles(path)
|
||||||
|
|
||||||
|
@ -291,7 +302,7 @@ func walk(path string, node *FileNode) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列出 dirname 指定目录下的文件/目录名.
|
// listFiles lists names of files under the specified dirname.
|
||||||
func listFiles(dirname string) []string {
|
func listFiles(dirname string) []string {
|
||||||
f, _ := os.Open(dirname)
|
f, _ := os.Open(dirname)
|
||||||
|
|
||||||
|
@ -303,12 +314,12 @@ func listFiles(dirname string) []string {
|
||||||
dirs := []string{}
|
dirs := []string{}
|
||||||
files := []string{}
|
files := []string{}
|
||||||
|
|
||||||
// 排序:目录靠前,文件靠后
|
// sort: directories in front of files
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
fio, _ := os.Lstat(filepath.Join(dirname, name))
|
fio, _ := os.Lstat(filepath.Join(dirname, name))
|
||||||
|
|
||||||
if fio.IsDir() {
|
if fio.IsDir() {
|
||||||
// 排除 .git 目录
|
// exclude the .git direcitory
|
||||||
if ".git" == fio.Name() {
|
if ".git" == fio.Name() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -322,9 +333,9 @@ func listFiles(dirname string) []string {
|
||||||
return append(dirs, files...)
|
return append(dirs, files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据文件后缀获取文件树图标 CSS 类名.
|
// getIconSkin gets CSS class name of icon with the specified filename extension.
|
||||||
//
|
//
|
||||||
// CSS 类名可参考 zTree 文档.
|
// Refers to the zTree document for CSS class names.
|
||||||
func getIconSkin(filenameExtension string) string {
|
func getIconSkin(filenameExtension string) string {
|
||||||
if isImg(filenameExtension) {
|
if isImg(filenameExtension) {
|
||||||
return "ico-ztree-img "
|
return "ico-ztree-img "
|
||||||
|
@ -354,9 +365,9 @@ func getIconSkin(filenameExtension string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据文件后缀获取编辑器 mode.
|
// getEditorMode gets editor mode with the specified filename extension.
|
||||||
//
|
//
|
||||||
// 编辑器 mode 可参考 CodeMirror 文档.
|
// Refers to the CodeMirror document for modes.
|
||||||
func getEditorMode(filenameExtension string) string {
|
func getEditorMode(filenameExtension string) string {
|
||||||
switch filenameExtension {
|
switch filenameExtension {
|
||||||
case ".go":
|
case ".go":
|
||||||
|
@ -382,12 +393,12 @@ func getEditorMode(filenameExtension string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 path 指定的路径上创建文件.
|
// createFile creates file on the specified path.
|
||||||
//
|
//
|
||||||
// fileType:
|
// fileType:
|
||||||
//
|
//
|
||||||
// "f": 文件
|
// "f": file
|
||||||
// "d": 目录
|
// "d": directory
|
||||||
func createFile(path, fileType string) bool {
|
func createFile(path, fileType string) bool {
|
||||||
switch fileType {
|
switch fileType {
|
||||||
case "f":
|
case "f":
|
||||||
|
@ -422,7 +433,7 @@ func createFile(path, fileType string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除 path 指定路径的文件或目录.
|
// removeFile removes file on the specified path.
|
||||||
func removeFile(path string) bool {
|
func removeFile(path string) bool {
|
||||||
if err := os.RemoveAll(path); nil != err {
|
if err := os.RemoveAll(path); nil != err {
|
||||||
glog.Errorf("Removes [%s] failed: [%s]", path, err.Error())
|
glog.Errorf("Removes [%s] failed: [%s]", path, err.Error())
|
||||||
|
@ -435,7 +446,7 @@ func removeFile(path string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 dir 指定的目录(包含子目录)中的 extension 指定后缀的文件中搜索包含 text 文本的文件,类似 grep/findstr 命令.
|
// search finds file under the specified dir and its sub-directories with the specified text, likes the command grep/findstr.
|
||||||
func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
|
func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
|
||||||
if !strings.HasSuffix(dir, conf.PathSeparator) {
|
if !strings.HasSuffix(dir, conf.PathSeparator) {
|
||||||
dir += conf.PathSeparator
|
dir += conf.PathSeparator
|
||||||
|
@ -455,10 +466,10 @@ func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
|
||||||
path := dir + fileInfo.Name()
|
path := dir + fileInfo.Name()
|
||||||
|
|
||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
// 进入目录递归
|
// enter the directory recursively
|
||||||
snippets = search(path, extension, text, snippets)
|
snippets = search(path, extension, text, snippets)
|
||||||
} else if strings.HasSuffix(path, extension) {
|
} else if strings.HasSuffix(path, extension) {
|
||||||
// 在文件中进行搜索
|
// grep in file
|
||||||
ss := searchInFile(path, text)
|
ss := searchInFile(path, text)
|
||||||
|
|
||||||
snippets = append(snippets, ss...)
|
snippets = append(snippets, ss...)
|
||||||
|
@ -468,7 +479,7 @@ func search(dir, extension, text string, snippets []*Snippet) []*Snippet {
|
||||||
return snippets
|
return snippets
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 path 指定的文件内容中搜索 text 指定的文本.
|
// searchInFile finds file with the specified path and text.
|
||||||
func searchInFile(path string, text string) []*Snippet {
|
func searchInFile(path string, text string) []*Snippet {
|
||||||
ret := []*Snippet{}
|
ret := []*Snippet{}
|
||||||
|
|
||||||
|
@ -495,7 +506,7 @@ func searchInFile(path string, text string) []*Snippet {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据文件名后缀判断是否是图片文件.
|
// isImg determines whether the specified extension is a image.
|
||||||
func isImg(extension string) bool {
|
func isImg(extension string) bool {
|
||||||
ext := strings.ToLower(extension)
|
ext := strings.ToLower(extension)
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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": "ヒント",
|
||||||
|
|
|
@ -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": "提示",
|
||||||
|
|
|
@ -3,7 +3,6 @@ package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -21,7 +20,8 @@ const (
|
||||||
Warn = "WARN" // 通知.严重程度:WARN
|
Warn = "WARN" // 通知.严重程度:WARN
|
||||||
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(¬ification)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,9 @@ func AddUser(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)
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
var args map[string]interface{}
|
var args map[string]interface{}
|
||||||
|
|
||||||
if err := decoder.Decode(&args); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
data["succ"] = false
|
data["succ"] = false
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue