Skip to content

Instantly share code, notes, and snippets.

@koyachi
Created December 9, 2012 09:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koyachi/4244025 to your computer and use it in GitHub Desktop.
Save koyachi/4244025 to your computer and use it in GitHub Desktop.
package main
// Usage:
// % go run wstail.go a.txt
// or
// % go build wstail.go
// % wstail a.txt
import (
"code.google.com/p/go.net/websocket"
"fmt"
"io"
"net/http"
"os"
"os/exec"
)
func indexHandler(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, `<html>
<head>
<style>
body
{ color: #1a2c37;
font-family: 'Helvetica', sans-serif; font-size: 86%;
padding: 2em; }
#info
{ font-size: 120%;
font-weight: bold; }
#tail
{ border: 1px solid #ccc;
height: 300px;
padding: 0.5em;
overflow: hidden;
position: relative;
overflow-y: scroll; }
</style>
<script type="text/javascript">
var header = "[wstail]"
var ws;
function init() {
console.log("init");
if (ws != null) {
ws.close();
ws = null;
}
path = "/tail";
console.log("path:" + path);
var div = document.getElementById("tail");
div.innerText = div.innerText + header + "path:" + path + "\n";
ws = new WebSocket("ws://localhost:23456" + path);
ws.onopen = function () {
div.innerText = div.innerText + header + "opened\n";
};
ws.onmessage = function (e) {
console.log(e.data);
div.innerText = div.innerText + e.data;
if (e.data instanceof ArrayBuffer) {
s = "ArrayBuffer: " + e.data.byteLength + "[";
var view = new Uint8Array(e.data);
for (var i = 0; i < view.length; ++i) {
s += " " + view[i];
}
s += "]";
div.innerText = div.innerText + s + "\n";
}
};
ws.onclose = function (e) {
div.innerText = div.innerText + header + "closed\n";
};
console.log("init");
div.innerText = div.innerText + header + "init\n";
};
</script>
<body onLoad="init();">
<pre id="info"></pre>
<pre id="tail"></pre>
</html>
`)
}
func startTail(file string, ch chan string) error {
tail := exec.Command("tail", "-f", file)
stdout, err := tail.StdoutPipe()
if err != nil {
return err
}
if err := tail.Start(); err != nil {
return err
}
go func() {
buf := make([]byte, 4*1024)
for {
//buf := make([]byte, 100)
n, err := stdout.Read(buf)
if err != nil {
panic("reader.ReadString(): " + err.Error())
return
}
line := string(buf[0:n])
fmt.Printf("read[%v:%v]\n", n, line)
ch <- line
}
}()
return nil
}
func makeWebsocketHandlerWithChannel(ch chan string, f func(chan string, *websocket.Conn)) func(*websocket.Conn) {
return func(ws *websocket.Conn) {
f(ch, ws)
}
}
func websocketTailHandler(ch chan string, ws *websocket.Conn) {
fmt.Printf("tailHandler %v\n", ws)
for {
line := <-ch
if err := websocket.Message.Send(ws, line); err != nil {
fmt.Println("ERR:websoket.Message.Send(): " + err.Error())
}
fmt.Printf("tailHandler write[%v]\n", line)
}
fmt.Println("tailHandler finished")
}
// for debug
func pseudoSubscriber(ch chan string) {
for {
line := <-ch
fmt.Println("[sub]: " + line)
}
}
func main() {
ch := make(chan string)
http.Handle("/tail", websocket.Handler(makeWebsocketHandlerWithChannel(ch, websocketTailHandler)))
http.HandleFunc("/", indexHandler)
if err := startTail(os.Args[1], ch); err != nil {
panic(err)
}
fmt.Println("start wstail...")
err := http.ListenAndServe(":23456", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
//pseudoSubscriber(ch)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment