This commit is contained in:
parent
7c12459c5d
commit
c3b6be3124
|
@ -29,6 +29,7 @@ type conf struct {
|
||||||
EditorChannel string
|
EditorChannel string
|
||||||
OutputChannel string
|
OutputChannel string
|
||||||
ShellChannel string
|
ShellChannel string
|
||||||
|
SessionChannel string
|
||||||
StaticResourceVersion string
|
StaticResourceVersion string
|
||||||
MaxProcs int
|
MaxProcs int
|
||||||
RuntimeMode string
|
RuntimeMode string
|
||||||
|
@ -166,11 +167,14 @@ func Load() {
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.V(3).Infof("IP [%s]", ip)
|
glog.V(3).Infof("IP [%s]", ip)
|
||||||
|
|
||||||
|
// TODO: 弄个反射吧?
|
||||||
Wide.Server = strings.Replace(Wide.Server, "{IP}", ip, 1)
|
Wide.Server = strings.Replace(Wide.Server, "{IP}", ip, 1)
|
||||||
Wide.StaticServer = strings.Replace(Wide.StaticServer, "{IP}", ip, 1)
|
Wide.StaticServer = strings.Replace(Wide.StaticServer, "{IP}", ip, 1)
|
||||||
Wide.EditorChannel = strings.Replace(Wide.EditorChannel, "{IP}", ip, 1)
|
Wide.EditorChannel = strings.Replace(Wide.EditorChannel, "{IP}", ip, 1)
|
||||||
Wide.OutputChannel = strings.Replace(Wide.OutputChannel, "{IP}", ip, 1)
|
Wide.OutputChannel = strings.Replace(Wide.OutputChannel, "{IP}", ip, 1)
|
||||||
Wide.ShellChannel = strings.Replace(Wide.ShellChannel, "{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])
|
file, _ := exec.LookPath(os.Args[0])
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"EditorChannel": "ws://{IP}:7070",
|
"EditorChannel": "ws://{IP}:7070",
|
||||||
"OutputChannel": "ws://{IP}:7070",
|
"OutputChannel": "ws://{IP}:7070",
|
||||||
"ShellChannel": "ws://{IP}:7070",
|
"ShellChannel": "ws://{IP}:7070",
|
||||||
|
"SessionChannel": "ws://{IP}:7070",
|
||||||
"StaticResourceVersion": "201409032040",
|
"StaticResourceVersion": "201409032040",
|
||||||
"MaxProcs": 4,
|
"MaxProcs": 4,
|
||||||
"RuntimeMode": "dev",
|
"RuntimeMode": "dev",
|
||||||
|
|
|
@ -7,11 +7,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 50; i++ {
|
||||||
fmt.Println("Hello, 世界", pkg.Now())
|
fmt.Println("Hello, 世界", pkg.Now())
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
time.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
1
main.go
1
main.go
|
@ -98,6 +98,7 @@ func main() {
|
||||||
|
|
||||||
// IDE 首页
|
// IDE 首页
|
||||||
http.HandleFunc("/", indexHandler)
|
http.HandleFunc("/", indexHandler)
|
||||||
|
http.HandleFunc("/session/ws", session.WSHandler)
|
||||||
|
|
||||||
// 运行相关
|
// 运行相关
|
||||||
http.HandleFunc("/build", output.BuildHandler)
|
http.HandleFunc("/build", output.BuildHandler)
|
||||||
|
|
|
@ -105,9 +105,7 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output := ""
|
ret = map[string]interface{}{"output": "", "cmd": "notification-output"}
|
||||||
|
|
||||||
ret = map[string]interface{}{"output": output, "cmd": "notification-output"}
|
|
||||||
|
|
||||||
if err := wsChan.Conn.WriteJSON(&ret); err != nil {
|
if err := wsChan.Conn.WriteJSON(&ret); err != nil {
|
||||||
glog.Error("Notification WS ERROR: " + err.Error())
|
glog.Error("Notification WS ERROR: " + err.Error())
|
||||||
|
|
|
@ -8,20 +8,27 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/b3log/wide/event"
|
"github.com/b3log/wide/event"
|
||||||
|
"github.com/b3log/wide/util"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SessionStateActive = iota // 会话状态:活的
|
SessionStateActive = iota // 会话状态:活的
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 输出通道.
|
||||||
|
// <sid, *util.WSChannel>
|
||||||
|
var sessionWS = map[string]*util.WSChannel{}
|
||||||
|
|
||||||
// 用户 HTTP 会话,用于验证登录.
|
// 用户 HTTP 会话,用于验证登录.
|
||||||
var HTTPSession = sessions.NewCookieStore([]byte("BEYOND"))
|
var HTTPSession = sessions.NewCookieStore([]byte("BEYOND"))
|
||||||
|
|
||||||
|
@ -44,6 +51,65 @@ var WideSessions Sessions
|
||||||
// 排它锁,防止并发修改.
|
// 排它锁,防止并发修改.
|
||||||
var mutex sync.Mutex
|
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) {
|
func (s *WideSession) SetProcesses(ps []*os.Process) {
|
||||||
s.Processes = ps
|
s.Processes = ps
|
||||||
|
@ -105,7 +171,9 @@ func (sessions *Sessions) Remove(sid string) {
|
||||||
if s.Id == sid {
|
if s.Id == sid {
|
||||||
*sessions = append((*sessions)[:i], (*sessions)[i+1:]...)
|
*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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
};
|
||||||
|
|
|
@ -171,18 +171,19 @@
|
||||||
channel: {
|
channel: {
|
||||||
editor: {{.conf.EditorChannel}},
|
editor: {{.conf.EditorChannel}},
|
||||||
shell: {{.conf.ShellChannel}},
|
shell: {{.conf.ShellChannel}},
|
||||||
output: {{.conf.OutputChannel}}
|
output: {{.conf.OutputChannel}},
|
||||||
|
session: {{.conf.SessionChannel}}
|
||||||
},
|
},
|
||||||
wideSessionId: {{.session.Id}}
|
wideSessionId: {{.session.Id}}
|
||||||
};
|
};
|
||||||
// 发往 Wide 的所有 AJAX 请求需要使用该函数创建请求参数.
|
// 发往 Wide 的所有 AJAX 请求需要使用该函数创建请求参数.
|
||||||
function newWideRequest() {
|
function newWideRequest() {
|
||||||
var ret = {
|
var ret = {
|
||||||
sid: config.wideSessionId
|
sid: config.wideSessionId
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/lib/jquery-2.1.1.min.js"></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/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/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/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/menu.js?{{.conf.StaticResourceVersion}}"></script>
|
||||||
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/hotkeys.js?{{.conf.StaticResourceVersion}}"></script>
|
<script type="text/javascript" src="{{.conf.StaticServer}}/static/js/hotkeys.js?{{.conf.StaticResourceVersion}}"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue