diff --git a/_examples/README.md b/_examples/README.md index bcc154a1..b61c2b7f 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -172,6 +172,7 @@ * [BoltDB](sessions/database/boltdb/main.go) * [Redis](sessions/database/redis/main.go) * Websocket + * [Gorilla FileWatch (3rd-party)](websocket/gorilla-filewatch/main.go) * [Basic](websocket/basic) * [Server](websocket/basic/server.go) * [Go Client](websocket/basic/go-client/client.go) diff --git a/_examples/websocket/gorilla-filewatch/go.mod b/_examples/websocket/gorilla-filewatch/go.mod new file mode 100644 index 00000000..5d77f753 --- /dev/null +++ b/_examples/websocket/gorilla-filewatch/go.mod @@ -0,0 +1,10 @@ +module gorilla-filewatch-example + +go 1.14 + +require ( + github.com/gorilla/websocket v1.4.2 + github.com/kataras/iris/v12 v12.1.8 +) + +replace github.com/kataras/iris/v12 => ../../../ diff --git a/_examples/websocket/gorilla-filewatch/main.go b/_examples/websocket/gorilla-filewatch/main.go new file mode 100644 index 00000000..e740c707 --- /dev/null +++ b/_examples/websocket/gorilla-filewatch/main.go @@ -0,0 +1,168 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// This example shows a use case with gorilla webscokets package +// sends a file to the browser client for display whenever the file is modified. +// +// $ go run main.go +// # Open http://localhost:8080/ . +// # Modify the file to see it update in the browser. +package main + +import ( + "flag" + "io/ioutil" + "log" + "os" + "strconv" + "time" + + "github.com/gorilla/websocket" + "github.com/kataras/iris/v12" +) + +const ( + // Time allowed to write the file to the client. + writeWait = 10 * time.Second + + // Time allowed to read the next pong message from the client. + pongWait = 60 * time.Second + + // Send pings to client with this period. Must be less than pongWait. + pingPeriod = (pongWait * 9) / 10 + + // Poll file for changes with this period. + filePeriod = 10 * time.Second +) + +var ( + addr = flag.String("addr", ":8080", "http service address") + filename string + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } +) + +func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) { + fi, err := os.Stat(filename) + if err != nil { + return nil, lastMod, err + } + if !fi.ModTime().After(lastMod) { + return nil, lastMod, nil + } + p, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fi.ModTime(), err + } + return p, fi.ModTime(), nil +} + +func reader(ws *websocket.Conn) { + defer ws.Close() + ws.SetReadLimit(512) + ws.SetReadDeadline(time.Now().Add(pongWait)) + ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) + for { + _, _, err := ws.ReadMessage() + if err != nil { + break + } + } +} + +func writer(ws *websocket.Conn, lastMod time.Time) { + lastError := "" + pingTicker := time.NewTicker(pingPeriod) + fileTicker := time.NewTicker(filePeriod) + defer func() { + pingTicker.Stop() + fileTicker.Stop() + ws.Close() + }() + for { + select { + case <-fileTicker.C: + var p []byte + var err error + + p, lastMod, err = readFileIfModified(lastMod) + + if err != nil { + if s := err.Error(); s != lastError { + lastError = s + p = []byte(lastError) + } + } else { + lastError = "" + } + + if p != nil { + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.TextMessage, p); err != nil { + return + } + } + case <-pingTicker.C: + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { + return + } + } + } +} + +func serveWs(ctx iris.Context) { + ws, err := upgrader.Upgrade(ctx.ResponseWriter(), ctx.Request(), nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + log.Println(err) + } + return + } + + var lastMod time.Time + if n, err := strconv.ParseInt(ctx.FormValue("lastMod"), 16, 64); err == nil { + lastMod = time.Unix(0, n) + } + + go writer(ws, lastMod) + reader(ws) +} + +func serveHome(ctx iris.Context) { + p, lastMod, err := readFileIfModified(time.Time{}) + if err != nil { + p = []byte(err.Error()) + lastMod = time.Unix(0, 0) + } + var v = struct { + Host string + Data string + LastMod string + }{ + ctx.Host(), + string(p), + strconv.FormatInt(lastMod.UnixNano(), 16), + } + ctx.View("home.html", v) +} + +// $ go get github.com/gorilla/websocket +// $ go run main.go testfile.txt +func main() { + flag.Parse() + if flag.NArg() != 1 { + log.Fatal("filename not specified") + } + filename = flag.Args()[0] + + app := iris.New() + app.RegisterView(iris.HTML("./views", ".html")) + app.Get("/", serveHome) + app.Any("/ws", serveWs) + + app.Listen(*addr) +} diff --git a/_examples/websocket/gorilla-filewatch/testfile.txt b/_examples/websocket/gorilla-filewatch/testfile.txt new file mode 100644 index 00000000..21b4fc73 --- /dev/null +++ b/_examples/websocket/gorilla-filewatch/testfile.txt @@ -0,0 +1,4 @@ +Some Contents +# you can edit this file locally +# and http://localhost:8080 +# will render the new contents through the live websocket connection. \ No newline at end of file diff --git a/_examples/websocket/gorilla-filewatch/views/home.html b/_examples/websocket/gorilla-filewatch/views/home.html new file mode 100644 index 00000000..e8e1d1d9 --- /dev/null +++ b/_examples/websocket/gorilla-filewatch/views/home.html @@ -0,0 +1,22 @@ + + + + WebSocket Example + + +
{{.Data}}
+ + + \ No newline at end of file