master
codeskyblue 8 years ago
parent 9d642f8b9f
commit dd0c7549cb

@ -17,3 +17,7 @@ body {
.navbar ul.navbar-nav>li>a {
color: white;
}
.realtime-log {
height: 50em;
}

@ -39,6 +39,11 @@
</div>
</nav>
<div class="container">
<div class="col-md-12">
<div class="alert alert-danger" role="alert" v-if="!isConnectionAlive">
<strong>Connection lost</strong> try to reconnect after 3s, or <a href="/" class="alert-link">connect immediately</a>
</div>
</div>
<div class="col-md-12">
<button class="btn btn-default btn-sm" id="launchNewProgram">
<span class="glyphicon glyphicon-plus"></span> New Program
@ -144,6 +149,32 @@
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<div class="modal" id="modalTailf">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form id="formNewProgram" action="/api/programs" method="post">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Tail</h4>
</div>
<div class="modal-body">
<p>Line: {{log.line_count}}</p>
<pre v-html="log.content" class="realtime-log"></pre>
<div class="checkbox text-right">
<label>
<input v-model="log.follow" type="checkbox"> Follow
</label>
</div>
</div>
<!-- <div class="modal-footer">
</div> -->
</form>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
</div>
<script src="/res/js/jquery-3.1.0.min.js"></script>
<script src="/res/bootstrap-3.3.5/js/bootstrap.min.js"></script>
@ -160,11 +191,11 @@
backdrop: 'static',
})
});
// $("#newProgram").modal({
// show: true,
// // keyboard: false,
// backdrop: 'static',
// })
$("#modalTailf").modal({
show: true,
// keyboard: false,
backdrop: 'static',
})
});
</script>
</body>

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

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

Loading…
Cancel
Save