From c3b6be312412f38a7ea848e935e125df46f1dd29 Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Sat, 20 Sep 2014 00:56:32 +0800 Subject: [PATCH] #58 --- conf/wide.go | 4 ++ conf/wide.json | 1 + .../admin/src/mytest/time/main.go | 3 +- main.go | 1 + notification/notifications.go | 4 +- session/sessions.go | 70 ++++++++++++++++++- static/js/session.js | 19 +++++ view/index.html | 16 +++-- 8 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 static/js/session.js diff --git a/conf/wide.go b/conf/wide.go index 342b55f..4667bdb 100644 --- a/conf/wide.go +++ b/conf/wide.go @@ -29,6 +29,7 @@ type conf struct { EditorChannel string OutputChannel string ShellChannel string + SessionChannel string StaticResourceVersion string MaxProcs int RuntimeMode string @@ -166,11 +167,14 @@ func Load() { } glog.V(3).Infof("IP [%s]", ip) + + // TODO: 弄个反射吧? Wide.Server = strings.Replace(Wide.Server, "{IP}", ip, 1) Wide.StaticServer = strings.Replace(Wide.StaticServer, "{IP}", ip, 1) Wide.EditorChannel = strings.Replace(Wide.EditorChannel, "{IP}", ip, 1) Wide.OutputChannel = strings.Replace(Wide.OutputChannel, "{IP}", ip, 1) Wide.ShellChannel = strings.Replace(Wide.ShellChannel, "{IP}", ip, 1) + Wide.SessionChannel = strings.Replace(Wide.SessionChannel, "{IP}", ip, 1) // 获取当前执行路径 file, _ := exec.LookPath(os.Args[0]) diff --git a/conf/wide.json b/conf/wide.json index b809567..47ef6f9 100644 --- a/conf/wide.json +++ b/conf/wide.json @@ -4,6 +4,7 @@ "EditorChannel": "ws://{IP}:7070", "OutputChannel": "ws://{IP}:7070", "ShellChannel": "ws://{IP}:7070", + "SessionChannel": "ws://{IP}:7070", "StaticResourceVersion": "201409032040", "MaxProcs": 4, "RuntimeMode": "dev", diff --git a/data/user_workspaces/admin/src/mytest/time/main.go b/data/user_workspaces/admin/src/mytest/time/main.go index e7f652c..5cb2f19 100644 --- a/data/user_workspaces/admin/src/mytest/time/main.go +++ b/data/user_workspaces/admin/src/mytest/time/main.go @@ -7,11 +7,10 @@ import ( ) func main() { - for i := 0; i < 5; i++ { + for i := 0; i < 50; i++ { fmt.Println("Hello, 世界", pkg.Now()) time.Sleep(time.Second) - time. } } diff --git a/main.go b/main.go index 67ec1bb..6d29f18 100644 --- a/main.go +++ b/main.go @@ -98,6 +98,7 @@ func main() { // IDE 首页 http.HandleFunc("/", indexHandler) + http.HandleFunc("/session/ws", session.WSHandler) // 运行相关 http.HandleFunc("/build", output.BuildHandler) diff --git a/notification/notifications.go b/notification/notifications.go index bf783bb..e15860d 100644 --- a/notification/notifications.go +++ b/notification/notifications.go @@ -105,9 +105,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) { return } - output := "" - - ret = map[string]interface{}{"output": output, "cmd": "notification-output"} + ret = map[string]interface{}{"output": "", "cmd": "notification-output"} if err := wsChan.Conn.WriteJSON(&ret); err != nil { glog.Error("Notification WS ERROR: " + err.Error()) diff --git a/session/sessions.go b/session/sessions.go index 9fc3ced..f65b74b 100644 --- a/session/sessions.go +++ b/session/sessions.go @@ -8,20 +8,27 @@ package session import ( "math/rand" + "net/http" "os" "strconv" "sync" "time" "github.com/b3log/wide/event" + "github.com/b3log/wide/util" "github.com/golang/glog" "github.com/gorilla/sessions" + "github.com/gorilla/websocket" ) const ( SessionStateActive = iota // 会话状态:活的 ) +// 输出通道. +// +var sessionWS = map[string]*util.WSChannel{} + // 用户 HTTP 会话,用于验证登录. var HTTPSession = sessions.NewCookieStore([]byte("BEYOND")) @@ -44,6 +51,65 @@ var WideSessions Sessions // 排它锁,防止并发修改. var mutex sync.Mutex +// 建立会话通道. +// 通道断开时销毁会话状态,回收相关资源. +func WSHandler(w http.ResponseWriter, r *http.Request) { + sid := r.URL.Query()["sid"][0] + wSession := WideSessions.Get(sid) + if nil == wSession { + glog.Errorf("Session [%s] not found", sid) + + return + } + + conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024) + wsChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()} + + sessionWS[sid] = &wsChan + + ret := map[string]interface{}{"output": "Ouput initialized", "cmd": "init-session"} + wsChan.Conn.WriteJSON(&ret) + + glog.V(4).Infof("Open a new [Session Channel] with session [%s], %d", sid, len(sessionWS)) + + input := map[string]interface{}{} + + for { + if err := wsChan.Conn.ReadJSON(&input); err != nil { + glog.V(3).Infof("[Session Channel] of session [%s] disconnected, releases all resources with it", sid) + + s := WideSessions.Get(sid) + + // 关闭事件队列 + close(s.EventQueue.Queue) + + // 杀进程 + for _, p := range s.Processes { + if err := p.Kill(); nil != err { + glog.Errorf("Can't kill process [%d] of session [%s]", p.Pid, sid) + } else { + glog.V(3).Infof("Killed a process [%d] of session [%s]", p.Pid, sid) + } + } + + // TODO: 回收相关通道 + + WideSessions.Remove(sid) + + return + } + + ret = map[string]interface{}{"output": "", "cmd": "session-output"} + + if err := wsChan.Conn.WriteJSON(&ret); err != nil { + glog.Error("Session WS ERROR: " + err.Error()) + return + } + + wsChan.Time = time.Now() + } +} + // 设置会话关联的进程集. func (s *WideSession) SetProcesses(ps []*os.Process) { s.Processes = ps @@ -105,7 +171,9 @@ func (sessions *Sessions) Remove(sid string) { if s.Id == sid { *sessions = append((*sessions)[:i], (*sessions)[i+1:]...) - glog.V(3).Infof("Has [%d] wide sessions currently", len(*sessions)) + glog.V(3).Infof("Removed a session [%s], has [%d] wide sessions currently", sid, len(*sessions)) + + return } } } diff --git a/static/js/session.js b/static/js/session.js new file mode 100644 index 0000000..b37ef04 --- /dev/null +++ b/static/js/session.js @@ -0,0 +1,19 @@ +// 用于保持会话,如果该通道断开,则服务器端会销毁会话状态,回收相关资源. +var sessionWS = new WebSocket(config.channel.session + '/session/ws?sid=' + config.wideSessionId); +sessionWS.onopen = function () { + console.log('[session onopen] connected'); +}; + +sessionWS.onmessage = function (e) { + console.log('[session onmessage]' + e.data); + var data = JSON.parse(e.data); + +}; +sessionWS.onclose = function (e) { + console.log('[session onclose] disconnected (' + e.code + ')'); + delete sessionWS; +}; +sessionWS.onerror = function (e) { + console.log('[session onerror] ' + JSON.parse(e)); +}; + diff --git a/view/index.html b/view/index.html index 39f3748..f570544 100644 --- a/view/index.html +++ b/view/index.html @@ -171,18 +171,19 @@ channel: { editor: {{.conf.EditorChannel}}, shell: {{.conf.ShellChannel}}, - output: {{.conf.OutputChannel}} + output: {{.conf.OutputChannel}}, + session: {{.conf.SessionChannel}} }, wideSessionId: {{.session.Id}} }; // 发往 Wide 的所有 AJAX 请求需要使用该函数创建请求参数. - function newWideRequest() { - var ret = { + function newWideRequest() { + var ret = { sid: config.wideSessionId - } - - return ret; - } + } + + return ret; + } @@ -225,6 +226,7 @@ +