This commit is contained in:
Liang Ding 2014-09-20 00:56:32 +08:00
parent 7c12459c5d
commit c3b6be3124
8 changed files with 105 additions and 13 deletions

View File

@ -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])

View File

@ -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",

View File

@ -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.
}
}

View File

@ -98,6 +98,7 @@ func main() {
// IDE 首页
http.HandleFunc("/", indexHandler)
http.HandleFunc("/session/ws", session.WSHandler)
// 运行相关
http.HandleFunc("/build", output.BuildHandler)

View File

@ -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())

View File

@ -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 // 会话状态:活的
)
// 输出通道.
// <sid, *util.WSChannel>
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
}
}
}

19
static/js/session.js Normal file
View File

@ -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));
};

View File

@ -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;
}
</script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/lib/jquery-2.1.1.min.js"></script>
@ -225,6 +226,7 @@
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/notification.js?{{.conf.StaticResourceVersion}}"></script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/tree.js?{{.conf.StaticResourceVersion}}"></script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/wide.js?{{.conf.StaticResourceVersion}}"></script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/session.js?{{.conf.StaticResourceVersion}}"></script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/menu.js?{{.conf.StaticResourceVersion}}"></script>
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/hotkeys.js?{{.conf.StaticResourceVersion}}"></script>
</body>