This commit is contained in:
Liang Ding 2014-09-16 15:06:52 +08:00
parent 557ae06b0e
commit 07f38fd483
6 changed files with 61 additions and 68 deletions

View File

@ -44,8 +44,8 @@
WebSocket 用于后端推送数据给前端: WebSocket 用于后端推送数据给前端:
</p> </p>
<ul> <ul>
<li>输出窗口通道</li> <li>输出通道</li>
<li>通知窗口通道</li> <li>通知通道</li>
<li>Shell 通道</li> <li>Shell 通道</li>
</ul> </ul>

View File

@ -71,6 +71,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 主程序入口.
func main() { func main() {
runtime.GOMAXPROCS(conf.Wide.MaxProcs) runtime.GOMAXPROCS(conf.Wide.MaxProcs)

View File

@ -3,16 +3,14 @@ package notification
import ( import (
"net/http" "net/http"
"os"
"os/exec"
"runtime"
"time" "time"
"strconv" "strconv"
"github.com/b3log/wide/conf"
"github.com/b3log/wide/event" "github.com/b3log/wide/event"
"github.com/b3log/wide/i18n" "github.com/b3log/wide/i18n"
"github.com/b3log/wide/user" "github.com/b3log/wide/user"
"github.com/b3log/wide/util"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
@ -33,16 +31,9 @@ type Notification struct {
Message string `json:"message"` Message string `json:"message"`
} }
// 一个用户会话的 WebSocket 通道结构.
type WSChannel struct {
Conn *websocket.Conn // WebSocket 连接
Request *http.Request // 关联的 HTTP 请求
Time time.Time // 该通道最近一次使用时间
}
// 通知通道. // 通知通道.
// <sid, WSChannel> // <sid, util.WSChannel>
var notificationWSs = map[string]*WSChannel{} var notificationWSs = map[string]*util.WSChannel{}
// 用户事件处理:将事件转为通知,并通过通知通道推送给前端. // 用户事件处理:将事件转为通知,并通过通知通道推送给前端.
// 当用户事件队列接收到事件时将会调用该函数进行处理. // 当用户事件队列接收到事件时将会调用该函数进行处理.
@ -69,14 +60,17 @@ func event2Notification(e *event.Event) {
notification.Message = i18n.Get(wsChannel.Request, "notification_"+strconv.Itoa(e.Code)).(string) notification.Message = i18n.Get(wsChannel.Request, "notification_"+strconv.Itoa(e.Code)).(string)
wsChannel.Conn.WriteJSON(&notification) wsChannel.Conn.WriteJSON(&notification)
wsChannel.Time = time.Now()
} }
// 建立通知通道.
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")
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, Request: r, Time: time.Now()} wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}
notificationWSs[sid] = &wsChan notificationWSs[sid] = &wsChan
@ -114,43 +108,3 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
} }
func pipeCommands(username string, commands ...*exec.Cmd) string {
for i, command := range commands[:len(commands)-1] {
setCmdEnv(command, username)
stdout, err := command.StdoutPipe()
if nil != err {
return err.Error()
}
command.Start()
commands[i+1].Stdin = stdout
}
last := commands[len(commands)-1]
setCmdEnv(last, username)
out, err := last.CombinedOutput()
if err != nil {
return err.Error()
}
return string(out)
}
func setCmdEnv(cmd *exec.Cmd, username string) {
userWorkspace := conf.Wide.GetUserWorkspace(username)
cmd.Env = append(cmd.Env,
"TERM="+os.Getenv("TERM"),
"GOPATH="+userWorkspace,
"GOOS="+runtime.GOOS,
"GOARCH="+runtime.GOARCH,
"GOROOT="+runtime.GOROOT(),
"PATH="+os.Getenv("PATH"))
cmd.Dir = userWorkspace
}

View File

@ -11,6 +11,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/b3log/wide/conf" "github.com/b3log/wide/conf"
"github.com/b3log/wide/user" "github.com/b3log/wide/user"
@ -19,16 +20,22 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
var outputWS = map[string]*websocket.Conn{} // 输出通道.
// <sid, util.WSChannel>
var outputWS = map[string]*util.WSChannel{}
// 建立输出通道.
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")
sid := session.Values["id"].(string) sid := session.Values["id"].(string)
outputWS[sid], _ = websocket.Upgrade(w, r, nil, 1024, 1024) conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}
outputWS[sid] = &wsChan
ret := map[string]interface{}{"output": "Ouput initialized", "cmd": "init-output"} ret := map[string]interface{}{"output": "Ouput initialized", "cmd": "init-output"}
outputWS[sid].WriteJSON(&ret) wsChan.Conn.WriteJSON(&ret)
glog.V(4).Infof("Open a new [Output] with session [%s], %d", sid, len(outputWS)) glog.V(4).Infof("Open a new [Output] with session [%s], %d", sid, len(outputWS))
} }
@ -96,7 +103,9 @@ func RunHandler(w http.ResponseWriter, r *http.Request) {
channelRet["cmd"] = "run" channelRet["cmd"] = "run"
if nil != outputWS[sid] { if nil != outputWS[sid] {
err := outputWS[sid].WriteJSON(&channelRet) wsChannel := outputWS[sid]
err := wsChannel.Conn.WriteJSON(&channelRet)
if nil != err { if nil != err {
glog.Error(err) glog.Error(err)
break break
@ -250,7 +259,8 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
if nil != outputWS[sid] { if nil != outputWS[sid] {
glog.V(3).Infof("Session [%s] 's build [id=%d, file=%s] has done", sid, runningId, filePath) glog.V(3).Infof("Session [%s] 's build [id=%d, file=%s] has done", sid, runningId, filePath)
err := outputWS[sid].WriteJSON(&channelRet) wsChannel := outputWS[sid]
err := wsChannel.Conn.WriteJSON(&channelRet)
if nil != err { if nil != err {
glog.Error(err) glog.Error(err)
} }
@ -371,7 +381,8 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
if nil != outputWS[sid] { if nil != outputWS[sid] {
glog.V(3).Infof("Session [%s] 's running [go install] [id=%d, dir=%s] has done", sid, runningId, curDir) glog.V(3).Infof("Session [%s] 's running [go install] [id=%d, dir=%s] has done", sid, runningId, curDir)
err := outputWS[sid].WriteJSON(&channelRet) wsChannel := outputWS[sid]
err := wsChannel.Conn.WriteJSON(&channelRet)
if nil != err { if nil != err {
glog.Error(err) glog.Error(err)
} }
@ -447,7 +458,9 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
channelRet["cmd"] = "go get" channelRet["cmd"] = "go get"
if nil != outputWS[sid] { if nil != outputWS[sid] {
err := outputWS[sid].WriteJSON(&channelRet) wsChannel := outputWS[sid]
err := wsChannel.Conn.WriteJSON(&channelRet)
if nil != err { if nil != err {
glog.Error(err) glog.Error(err)
break break

View File

@ -10,16 +10,21 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/b3log/wide/conf" "github.com/b3log/wide/conf"
"github.com/b3log/wide/i18n" "github.com/b3log/wide/i18n"
"github.com/b3log/wide/user" "github.com/b3log/wide/user"
"github.com/b3log/wide/util"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
var shellWS = map[string]*websocket.Conn{} // Shell 通道.
// <sid, util.WSChannel>>
var shellWS = map[string]*util.WSChannel{}
// Shell 首页.
func IndexHandler(w http.ResponseWriter, r *http.Request) { func IndexHandler(w http.ResponseWriter, r *http.Request) {
i18n.Load() i18n.Load()
@ -53,22 +58,26 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 建立 Shell 通道.
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) username := session.Values["username"].(string)
sid := session.Values["id"].(string) sid := session.Values["id"].(string)
shellWS[sid], _ = websocket.Upgrade(w, r, nil, 1024, 1024) conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}
shellWS[sid] = &wsChan
ret := map[string]interface{}{"output": "Shell initialized", "cmd": "init-shell"} ret := map[string]interface{}{"output": "Shell initialized", "cmd": "init-shell"}
shellWS[sid].WriteJSON(&ret) wsChan.Conn.WriteJSON(&ret)
glog.Infof("Open a new [Shell] with session [%s], %d", sid, len(shellWS)) glog.Infof("Open a new [Shell] with session [%s], %d", sid, len(shellWS))
input := map[string]interface{}{} input := map[string]interface{}{}
for { for {
if err := shellWS[sid].ReadJSON(&input); err != nil { if err := wsChan.Conn.ReadJSON(&input); err != nil {
if err.Error() == "EOF" { if err.Error() == "EOF" {
return return
} }
@ -104,7 +113,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
ret = map[string]interface{}{"output": output, "cmd": "shell-output"} ret = map[string]interface{}{"output": output, "cmd": "shell-output"}
if err := shellWS[sid].WriteJSON(&ret); err != nil { if err := wsChan.Conn.WriteJSON(&ret); err != nil {
glog.Error("Shell WS ERROR: " + err.Error()) glog.Error("Shell WS ERROR: " + err.Error())
return return
} }

16
util/websocket.go Normal file
View File

@ -0,0 +1,16 @@
package util
import (
"net/http"
"time"
"github.com/gorilla/websocket"
)
// 一个用户会话的 WebSocket 通道结构.
type WSChannel struct {
Sid string // 用户会话 id
Conn *websocket.Conn // WebSocket 连接
Request *http.Request // 关联的 HTTP 请求
Time time.Time // 该通道最近一次使用时间
}