This commit is contained in:
parent
db0c3992d0
commit
24c75e8125
15
conf/wide.go
15
conf/wide.go
|
@ -9,6 +9,7 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/event"
|
||||
_ "github.com/b3log/wide/i18n"
|
||||
|
@ -38,9 +39,12 @@ type conf struct {
|
|||
var Wide conf
|
||||
var rawWide conf
|
||||
|
||||
// 检查 Wide 运行环境.
|
||||
// 定时检查 Wide 运行环境.
|
||||
// 如果是特别严重的问题(比如 $GOPATH 不存在)则退出进程。另一些不太严重的问题(比如 gocode 不存在)则放入全局通知队列。
|
||||
func (*conf) CheckEnv() {
|
||||
func CheckEnv() {
|
||||
go func() {
|
||||
for {
|
||||
|
||||
if "" == os.Getenv("GOPATH") {
|
||||
glog.Fatal("Not found $GOPATH")
|
||||
os.Exit(-1)
|
||||
|
@ -67,6 +71,10 @@ func (*conf) CheckEnv() {
|
|||
event.EventQueue <- event.EvtIDEStubNotFound
|
||||
glog.Warningf("Not found ide_stub [%s]", ide_stub)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 获取 username 指定的用户的工作空间路径.
|
||||
|
@ -140,9 +148,6 @@ func Save() bool {
|
|||
|
||||
// 加载 Wide 配置.
|
||||
func Load() {
|
||||
// 检查 Wide 运行环境
|
||||
Wide.CheckEnv()
|
||||
|
||||
bytes, _ := ioutil.ReadFile("conf/wide.json")
|
||||
|
||||
err := json.Unmarshal(bytes, &Wide)
|
||||
|
|
|
@ -1,38 +1,55 @@
|
|||
// 事件处理.
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
import "github.com/golang/glog"
|
||||
|
||||
const (
|
||||
EvtGOPATHNotFound = iota // 事件:找不到环境变量 $GOPATH
|
||||
EvtGOROOTNotFound // 事件:找不到环境变量 $GOROOT
|
||||
EvtGocodeNotFount // 事件:找不到 gocode
|
||||
EvtIDEStubNotFound // 事件:找不到 IDE stub
|
||||
|
||||
)
|
||||
|
||||
const MaxQueueLength = 10
|
||||
|
||||
// 全局事件队列.
|
||||
// 入队的事件将分发到每个用户的通知队列.
|
||||
var EventQueue = make(chan int, 10)
|
||||
var EventQueue = make(chan int, MaxQueueLength)
|
||||
|
||||
// 用户事件队列.
|
||||
// 入队的事件将翻译为通知,并通过通知通道推送到前端.
|
||||
var UserEventQueue map[string]chan int
|
||||
var UserEventQueues = map[string]chan int{}
|
||||
|
||||
// 加载事件处理.
|
||||
func Load() {
|
||||
go func() {
|
||||
for {
|
||||
// 获取事件
|
||||
event := <-EventQueue
|
||||
|
||||
for event := range EventQueue {
|
||||
glog.V(5).Info("收到全局事件 [%d]", event)
|
||||
|
||||
// 将事件分发到每个用户的事件队列里
|
||||
for _, userQueue := range UserEventQueue {
|
||||
for _, userQueue := range UserEventQueues {
|
||||
userQueue <- event
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 添加一个用户事件队列.
|
||||
func InitUserQueue(sid string) {
|
||||
// FIXME: 会话过期后需要销毁对应的用户事件队列
|
||||
|
||||
q := UserEventQueues[sid]
|
||||
if nil != q {
|
||||
close(q)
|
||||
}
|
||||
|
||||
q = make(chan int, MaxQueueLength)
|
||||
UserEventQueues[sid] = q
|
||||
|
||||
go func() {
|
||||
for event := range q {
|
||||
glog.Infof("Session [%s] received a event [%d]", sid, event)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
7
main.go
7
main.go
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/file"
|
||||
"github.com/b3log/wide/i18n"
|
||||
"github.com/b3log/wide/notification"
|
||||
"github.com/b3log/wide/output"
|
||||
"github.com/b3log/wide/shell"
|
||||
"github.com/b3log/wide/user"
|
||||
|
@ -31,6 +32,9 @@ func init() {
|
|||
|
||||
// 加载配置
|
||||
conf.Load()
|
||||
|
||||
// 定时检查 Wide 运行环境
|
||||
conf.CheckEnv()
|
||||
}
|
||||
|
||||
// Wide 首页.
|
||||
|
@ -108,6 +112,9 @@ func main() {
|
|||
http.HandleFunc("/shell/ws", shell.WSHandler)
|
||||
http.HandleFunc("/shell", shell.IndexHandler)
|
||||
|
||||
// 通知
|
||||
http.HandleFunc("/notification/ws", notification.WSHandler)
|
||||
|
||||
// 用户
|
||||
http.HandleFunc("/user/new", user.AddUser)
|
||||
http.HandleFunc("/user/repos/init", user.InitGitRepos)
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/b3log/wide/conf"
|
||||
"github.com/b3log/wide/event"
|
||||
"github.com/b3log/wide/user"
|
||||
"github.com/golang/glog"
|
||||
"github.com/gorilla/websocket"
|
||||
|
@ -22,25 +23,42 @@ type Notification struct {
|
|||
Message string
|
||||
}
|
||||
|
||||
// 一个用户会话的 WebSocket 通道结构.
|
||||
type WSChannel struct {
|
||||
Conn *websocket.Conn // WebSocket 连接
|
||||
Time time.Time // 该通道最近一次使用时间
|
||||
}
|
||||
|
||||
// 通知通道.
|
||||
var notificationWS = map[string]*websocket.Conn{}
|
||||
// <username, {<sid1, WSChannel1>, <sid2, WSChannel2>}>
|
||||
var notificationWSs = map[string]map[string]WSChannel{}
|
||||
|
||||
func WSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
session, _ := user.Session.Get(r, "wide-session")
|
||||
username := session.Values["username"].(string)
|
||||
sid := session.Values["id"].(string)
|
||||
|
||||
notificationWS[sid], _ = websocket.Upgrade(w, r, nil, 1024, 1024)
|
||||
conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
|
||||
wsChan := WSChannel{Conn: conn, Time: time.Now()}
|
||||
|
||||
wsChans := notificationWSs[username]
|
||||
if nil == wsChans {
|
||||
wsChans = map[string]WSChannel{}
|
||||
}
|
||||
|
||||
wsChans[sid] = wsChan
|
||||
|
||||
ret := map[string]interface{}{"output": "Notification initialized", "cmd": "init-notification"}
|
||||
notificationWS[sid].WriteJSON(&ret)
|
||||
wsChan.Conn.WriteJSON(&ret)
|
||||
|
||||
glog.Infof("Open a new [Notification] with session [%s], %d", sid, len(notificationWS))
|
||||
glog.Infof("Open a new [Notification] with session [%s], %d", sid, len(wsChans))
|
||||
|
||||
event.InitUserQueue(sid)
|
||||
|
||||
input := map[string]interface{}{}
|
||||
|
||||
for {
|
||||
if err := notificationWS[sid].ReadJSON(&input); err != nil {
|
||||
if err := wsChan.Conn.ReadJSON(&input); err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
return
|
||||
}
|
||||
|
@ -49,35 +67,16 @@ func WSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
glog.Error("Shell WS ERROR: " + err.Error())
|
||||
glog.Error("Notification WS ERROR: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
inputCmd := input["cmd"].(string)
|
||||
|
||||
cmds := strings.Split(inputCmd, "|")
|
||||
commands := []*exec.Cmd{}
|
||||
for _, cmdWithArgs := range cmds {
|
||||
cmdWithArgs = strings.TrimSpace(cmdWithArgs)
|
||||
cmdWithArgs := strings.Split(cmdWithArgs, " ")
|
||||
args := []string{}
|
||||
if len(cmdWithArgs) > 1 {
|
||||
args = cmdWithArgs[1:]
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdWithArgs[0], args...)
|
||||
commands = append(commands, cmd)
|
||||
}
|
||||
|
||||
output := ""
|
||||
if !strings.Contains(inputCmd, "clear") {
|
||||
output = pipeCommands(username, commands...)
|
||||
}
|
||||
|
||||
ret = map[string]interface{}{"output": output, "cmd": "shell-output"}
|
||||
ret = map[string]interface{}{"output": output, "cmd": "notification-output"}
|
||||
|
||||
if err := notificationWS[sid].WriteJSON(&ret); err != nil {
|
||||
glog.Error("Shell WS ERROR: " + err.Error())
|
||||
if err := wsChan.Conn.WriteJSON(&ret); err != nil {
|
||||
glog.Error("Notification WS ERROR: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
var notificationWS = new WebSocket(config.channel.shell + '/notification/ws');
|
||||
notificationWS.onopen = function() {
|
||||
console.log('[notification onopen] connected');
|
||||
};
|
||||
notificationWS.onmessage = function(e) {
|
||||
console.log('[notification onmessage]' + e.data);
|
||||
var data = JSON.parse(e.data);
|
||||
if ('init-notification' !== data.cmd) {
|
||||
$('#notification').val(data.output);
|
||||
}
|
||||
};
|
||||
notificationWS.onclose = function(e) {
|
||||
console.log('[notification onclose] disconnected (' + e.code + ')');
|
||||
delete notificationWS;
|
||||
};
|
||||
notificationWS.onerror = function(e) {
|
||||
console.log('[notification onerror] ' + e);
|
||||
};
|
||||
|
||||
var notification = {
|
||||
init: function() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
notification.init();
|
||||
});
|
|
@ -143,6 +143,10 @@
|
|||
<textarea id="output"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<textarea id="notification"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -196,6 +200,7 @@
|
|||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/lint/go-lint.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/tabs.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/editor.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/notification.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/tree.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/wide.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
<script type="text/javascript" src="{{.Wide.StaticServer}}/static/js/menu.js?{{.Wide.StaticResourceVersion}}"></script>
|
||||
|
|
Loading…
Reference in New Issue