diff --git a/res/css/style.css b/res/css/style.css index 9ca9500..1860531 100644 --- a/res/css/style.css +++ b/res/css/style.css @@ -17,3 +17,7 @@ body { .navbar ul.navbar-nav>li>a { color: white; } + +.realtime-log { + height: 50em; +} diff --git a/res/index.html b/res/index.html index 97e7ac9..c741378 100644 --- a/res/index.html +++ b/res/index.html @@ -39,6 +39,11 @@
+
+ +
+ +
@@ -160,11 +191,11 @@ backdrop: 'static', }) }); - // $("#newProgram").modal({ - // show: true, - // // keyboard: false, - // backdrop: 'static', - // }) + $("#modalTailf").modal({ + show: true, + // keyboard: false, + backdrop: 'static', + }) }); diff --git a/res/js/index.js b/res/js/index.js index e5d2f7c..b66dcb2 100644 --- a/res/js/index.js +++ b/res/js/index.js @@ -12,8 +12,8 @@ function getQueryString(name) { return null; } -var ws; var wsProtocol = location.protocol == "https:" ? "wss" : "ws"; +var W = {}; var testPrograms = [{ program: { @@ -28,6 +28,12 @@ var testPrograms = [{ var vm = new Vue({ el: "#app", data: { + isConnectionAlive: true, + log: { + content: '', + follow: true, + line_count: 0, + }, programs: [], }, methods: { @@ -144,23 +150,67 @@ $(function() { e.preventDefault() }); - console.log("HEE") - ws = new WebSocket(wsProtocol + "://" + location.host + "/ws/events"); - ws.onopen = function(evt) { - console.log("OPEN"); - } - ws.onclose = function(evt) { - console.log("CLOSE"); - ws = null; - } - ws.onmessage = function(evt) { - console.log("response:" + evt.data); - vm.refresh(); - } - ws.onerror = function(evt) { - console.log("error:", evt.data); + + function newWebsocket(pathname, opts) { + var ws = new WebSocket(wsProtocol + "://" + location.host + pathname); + opts = opts || {}; + ws.onopen = opts.onopen || function(evt) { + console.log("WS OPEN", pathname); + } + ws.onclose = opts.onclose || function(evt) { + console.log("CLOSE"); + ws = null; + } + ws.onmessage = opts.onmessage || function(evt) { + console.log("response:" + evt.data); + } + ws.onerror = function(evt) { + console.error("error:", evt.data); + } + return ws; } - // ws.send("Hello") + console.log("HEE") + + function newEventWatcher() { + W.events = newWebsocket("/ws/events", { + onopen: function(evt) { + vm.isConnectionAlive = true; + }, + onmessage: function(evt) { + console.log("response:" + evt.data); + vm.refresh(); + }, + onclose: function(evt) { + W.events = null; + vm.isConnectionAlive = false; + console.log("Reconnect after 3s") + setTimeout(newEventWatcher, 3000) + } + }); + }; + + newEventWatcher(); + + // cancel follow log if people want to see the original data + $(".realtime-log").bind('mousewheel', function(evt) { + if (evt.originalEvent.wheelDelta >= 0) { + vm.log.follow = false; + } + }) + + var ws = newWebsocket("/ws/logs/hee", { + onopen: function(evt) { + vm.log.content = ""; + }, + onmessage: function(evt) { + vm.log.content += evt.data; + vm.log.line_count = $.trim(vm.log.content).split(/\r\n|\r|\n/).length; + if (vm.log.follow) { + var pre = $(".realtime-log")[0]; + pre.scrollTop = pre.scrollHeight; + } + } + }) }); diff --git a/web.go b/web.go index a4d5f77..b5cfe13 100644 --- a/web.go +++ b/web.go @@ -160,7 +160,7 @@ func (s *Supervisor) saveDB() error { func (s *Supervisor) renderHTML(w http.ResponseWriter, name string, data interface{}) { baseName := filepath.Base(name) - t := template.Must(template.New("t").ParseFiles(name)).Delims("[[", "]]") + t := template.Must(template.New("t").Delims("[[", "]]").ParseFiles(name)) t.ExecuteTemplate(w, baseName, data) } @@ -304,6 +304,27 @@ func (s *Supervisor) wsEvents(w http.ResponseWriter, r *http.Request) { } } +func (s *Supervisor) wsLog(w http.ResponseWriter, r *http.Request) { + name := mux.Vars(r)["name"] + log.Println(name) + + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Print("upgrade:", err) + return + } + defer c.Close() + n := 0 + for { + n += 1 + err := c.WriteMessage(1, []byte(strconv.Itoa(n)+" "+time.Now().Format(http.TimeFormat)+"Hello\n")) + if err != nil { + break + } + time.Sleep(500 * time.Millisecond) + } +} + func (s *Supervisor) catchExitSignal() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) @@ -340,6 +361,7 @@ func init() { r.HandleFunc("/api/programs/{name}/start", suv.hStartProgram).Methods("POST") r.HandleFunc("/api/programs/{name}/stop", suv.hStopProgram).Methods("POST") r.HandleFunc("/ws/events", suv.wsEvents) + r.HandleFunc("/ws/logs/{name}", suv.wsLog) fs := http.FileServer(http.Dir("res")) http.Handle("/", r)