golang gin websocket io tailf

html.go

 

package ws

 

import "text/template"

 

var (

    tailfHtml = `

    <!DOCTYPE html>

    <html lang="en">

        <head>

            <meta charset="utf-8">

            <title></title>

            <meta name="viewport" content="width=device-width, initial-scale=1.0">

            <style>

                body {background:#2C3E50; color:#2ECC71;}

                pre {width:100%; word-break:break-all; white-space:pre-wrap; word-wrap:break-word;}

            </style>

        </head>

        <body>

            <pre id="message"></pre>

            <script type="text/javascript">

                (function() {

                    var msg = document.getElementById('message');

                    var ws = new WebSocket(window.location.href.replace('http', 'ws'));

                    ws.onopen = function(evt) {

                        console.log('Connection opened');

                    }

                    ws.onclose = function(evt) {

                        console.log('Connection closed');

                    }

                    ws.onmessage = function(evt) {

                        try {

                            msg.innerText += decodeURIComponent(evt.data);

                        } catch(e) {

                        }

                    }

                })();

            </script>

        </body>

    </html>

`

    tailfTmpl = template.Must(template.New("").Parse(tailfHtml))

)

 wss.go

 

package ws

 

import (

    "net/http"

 

    "github.com/gorilla/websocket"

)

 

var (

    upgrader = websocket.Upgrader{

        ReadBufferSize: 1024,

        WriteBufferSize: 1024,

        CheckOrigin: func(r *http.Request) bool { // 解决跨域问题

            return true

        },

    }

)

tailf.go

 

package ws

 

import (

    "bytes"

    "goo"

    "net/url"

    "os"

    "time"

 

    "github.com/gin-gonic/gin"

    "github.com/gorilla/websocket"

)

 

type tailF struct {

    filename string

    conn *websocket.Conn

    send chan []byte

    fileOffset int64

}

 

func TailF(filename string) gin.HandlerFunc {

    return func(c *gin.Context) {

        if c.IsWebsocket() {

            conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)

            if err != nil {

                goo.Log().Error(err.Error())

                return

            }

            client := &tailF{

                filename: filename,

                conn: conn,

                send: make(chan []byte, 256),

            }

            go client.write()

            go client.read()

        } else {

            c.Header("Content-Type", "text/html; charset=utf-8")

            tailfTmpl.Execute(c.Writer, nil)

        }

    }

}

 

func (this *tailF) read() {

    ticker := time.NewTicker(1 * time.Second) // 定时器,每隔1秒执行一次

    defer func() {

        ticker.Stop()

        this.conn.Close()

    }()

    for {

        select {

        case <-ticker.C: // 捕获到一秒后的执行

            this.getData()

        }

    }

}

 

func (this *tailF) write() {

    ticker := time.NewTicker(pingPeriod)

    defer func() {

        ticker.Stop()

        this.conn.Close()

    }()

    for {

        select {

        case <-ticker.C:  // websocket ping

            this.conn.SetWriteDeadline(time.Now().Add(writeWait))

            if err := this.conn.WriteMessage(websocket.PingMessage, nil); err != nil {

                return

            }

        case message := <-this.send:

            this.conn.SetWriteDeadline(time.Now().Add(writeWait))

            if err := this.conn.WriteMessage(websocket.TextMessage, message); err != nil {

                return

            }

        }

    }

}

 

func (this *tailF) getData() {

    if this.filename == "" {

        this.filename = "log.log"

    }

 

    file, err := os.Open(this.filename)

    if err != nil {

        goo.Log().Error(err.Error())

        return

    }

    defer file.Close()

 

    info, _ := file.Stat()

    size := info.Size()

 

    if this.fileOffset == size {

        return

    }

 

    if this.fileOffset == 0 && size > maxMessageSize*2 {

        this.fileOffset = size - maxMessageSize*2

    }

 

    file.Seek(this.fileOffset, 1) // 0 means relative to the origin of the file, 1 means relative to the current offset, and 2 means relative to the end.

    this.fileOffset = size

 

    data := []byte{}

    for {

        buf := make([]byte, 1)  // 每次读取1个字节,直到读取到最后(避免产生多余的byte,当buf的初始大小 大于 内容的大小时,就会有多余的byte)

        _, err := file.Read(buf)

        if err != nil {

            break

        }

        data = append(data, buf...)

    }

 

    data = bytes.Replace(data, []byte("\x1b[0m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[31m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[32m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[33m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[34m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[35m"), []byte(""), -1)

    data = bytes.Replace(data, []byte("\x1b[36m"), []byte(""), -1)

 

    this.send <- []byte(url.PathEscape(string(data))) // urlencode编码处理特殊字符,url.PathEscape() 对应js的 decodeURIComponent()

}

const.go

 

package ws

 

import "time"

 

const (

    writeWait = 10 * time.Second

    pongWait = 60 * time.Second

    pingPeriod = (pongWait * 9) / 10

    filePeriod = 3 * time.Second

    maxMessageSize = 512

 说明:

1、http的url和ws的url一直,程序里面做了判断,并执行到不同的业务逻辑里面

2、文件内容包含有特殊字符,需要进行urlencode编码,服务端使用url.PathEscape()编码,前端使用decodeURIComponent()解密

3、每个url访问,都会单独建立一个websocket,所以监控文件时,每个ws链接,对应的是自己的fileoffset,所以需要把fileoffset提到tailF对象里面

4、ticker := time.NewTicker(1*time.Second) 用户创建定时器,定时器不用时需要不关闭, defer ticker.close()

5、发送ping消息可以通过定时器处理

6、发送文本消息,可以通过 chan []byte 通道处理,没有数据时,等待通道内容,有内容时,写入通道

转载于:https://my.oschina.net/qiongtaoli/blog/3007898

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值