React+Go+WEBSocket

React+Go+WEBSocket

React

import { Component } from 'react'
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
import Socket from './websocket';

import CodeMirror from '@uiw/react-codemirror';
import 'codemirror/keymap/sublime';
import 'codemirror/theme/monokai.css';
export default class JenkinsLog extends Component {
    state = {
        jenkinsterminal: new Terminal({
            // cursorStyle: 'block', // 光标样式
            // cursorBlink: true, // 光标闪烁
            theme: {
                foreground: '#dddddd', // 字体
                cursor: 'gray', // 设置光标
            },
            // windowsMode: true, // 自动换行
            // cols: 120,
        }),
        logData: "",
    }
    componentDidMount() {
        // 获取DOM实例
        // const jenkinsTerminalDOM = document.getElementById('jenkinsterminal');
        // 绑定DOM和Terminal实例
        // this.state.jenkinsterminal.open(jenkinsTerminalDOM);

        var socketUrl = "ws://127.0.0.1:8081"
        if (process.env.NODE_ENV === "production") {
            socketUrl = "wss://cmp.airudder.com"
        }
        this.socket = new Socket({
            socketUrl: `${socketUrl}/api/ws/jenkinslog`,
            timeout: 5000,
            socketMessage: (receive) => {
                console.log(receive);  //后端返回的数据,渲染页面
                // this.state.jenkinsterminal.write(receive.data)
                this.setState({ logData: receive.data })
            },
            socketClose: (msg) => {
                // const { setjenkinsLogVisible } = this.props
                // setjenkinsLogVisible(false)
                console.log(msg);
            },
            socketError: () => {
                console.log(this.state.taskStage + '连接建立失败');
            },
            socketOpen: () => {
                console.log('连接建立成功');
                // 心跳机制 定时向后端发数据
                const { jenkinsurl } = this.props
                this.socket.sendMessage(jenkinsurl)
            }
        });
        try {
            this.socket.connection();
        } catch (e) {
            console.log("捕获异常: ", e);
            // 捕获异常,防止js error
            // donothing
        }
    }
    render() {
        // const { jenkinsLog } = this.props
        // this.state.jenkinsterminal.write(jenkinsLog)
        return (
            // <div id="jenkinsterminal" />
            <CodeMirror
                value={this.state.logData}
                options={{
                    theme: 'monokai',
                    keyMap: 'sublime',
                    mode: 'jsx',
                    lineNumbers: false,
                }}
            />
        )
    }
}

WEBSocket

/**
 * 参数:[socketOpen|socketClose|socketMessage|socketError] = func,[socket连接成功时触发|连接关闭|发送消息|连接错误]
 * timeout:连接超时时间
 * @type {module.webSocket}
 */
module.exports = class webSocket {
    constructor(param = {}) {
        this.param = param;
        this.reconnectCount = 0;
        this.socket = null;
        this.taskRemindInterval = null;
        this.isSucces = true;
    }
    connection = () => {
        let { socketUrl, timeout = 0 } = this.param;
        // 检测当前浏览器是什么浏览器来决定用什么socket
        if ('WebSocket' in window) {
            console.log('WebSocket');

            this.socket = new WebSocket(socketUrl);
        }
        else if ('MozWebSocket' in window) {
            console.log('MozWebSocket');

            this.socket = new MozWebSocket(socketUrl);
        }
        else {
            console.log('SockJS');

            this.socket = new SockJS(socketUrl);
        }
        this.socket.onopen = this.onopen;
        this.socket.onmessage = this.onmessage;
        this.socket.onclose = this.onclose;
        this.socket.onerror = this.onerror;
        this.socket.sendMessage = this.sendMessage;
        this.socket.closeSocket = this.closeSocket;
        // 检测返回的状态码 如果socket.readyState不等于1则连接失败,关闭连接
        if (timeout) {
            let time = setTimeout(() => {
                if (this.socket && this.socket.readyState !== 1) {
                    this.socket.close();
                }
                clearInterval(time);
            }, timeout);
        }
    };
    // 连接成功触发
    onopen = () => {
        let { socketOpen } = this.param;
        this.isSucces = false  //连接成功将标识符改为false
        socketOpen && socketOpen();
    };
    // 后端向前端推得数据
    onmessage = (msg) => {
        let { socketMessage } = this.param;
        socketMessage && socketMessage(msg);
        // 打印出后端推得数据
        // console.log(msg);
    };
    // 关闭连接触发
    onclose = (e) => {
        this.isSucces = true   //关闭将标识符改为true
        console.log('关闭socket收到的数据');
        let { socketClose } = this.param;
        socketClose && socketClose(e);
        // 根据后端返回的状态码做操作
        // 我的项目是当前页面打开两个或者以上,就把当前以打开的socket关闭
        // 否则就20秒重连一次,直到重连成功为止 
        this.socket.close();
        // if (e.code == '4500') {
        //     this.socket.close();
        // } else {
        //     this.taskRemindInterval = setInterval(() => {
        //         if (this.isSucces) {
        //             this.connection();
        //         } else {
        //             clearInterval(this.taskRemindInterval)
        //         }
        //     }, 20000)
        // }
    };
    onerror = (e) => {
        // socket连接报错触发
        let { socketError } = this.param;
        this.socket = null;
        socketError && socketError(e);
    };
    sendMessage = (value) => {
        // 向后端发送数据
        if (this.socket) {
            this.socket.send(JSON.stringify(value));
        }
    };
};

GO

import (
	"github.com/gorilla/websocket"

)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 解决跨域问题
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}
func SocketHandler(w http.ResponseWriter, r *http.Request) {
	// Upgrade our raw HTTP connection to a websocket based one
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("Error during connection upgradation:", err)
		return
	}
	defer conn.Close()

	_, msgBytes, err := conn.ReadMessage()
	if err != nil {
		olog.GetLogger().Error("read message failed", zap.Error(err))
		return
	}
	jenkinsUrl := strings.Trim(string(msgBytes), `"`)
	if jenkinsUrl == "" {
		return
	}
	fmt.Println(jenkinsUrl)
	errCh := make(chan error)
	go func(errCh chan error) {
		_, _, err := conn.ReadMessage()
		errCh <- err
	}(errCh)
	var i int
	// releaseLogMgr := repos.NewReleaseAppLogMgr()
	for {
		ticker := time.NewTicker(2 * time.Second)
		select {
		case <-ticker.C:
			i++
			buildlog, err := tool.GetJenkinsBuildLog(jenkinsUrl)
			if err != nil {
				olog.GetLogger().Info("GetJenkinsBuildLog failed", zap.Error(err))
				return
			}
			connWriter, err := conn.NextWriter(websocket.TextMessage)
			if err != nil {
				olog.GetLogger().Error("get writer failed", zap.Error(err))
				continue
			}
			if _, err := connWriter.Write([]byte(buildlog)); err != nil {
				olog.GetLogger().Error("write message failed", zap.Error(err))
				continue
			}
			if connWriter != nil {
				connWriter.Close()
			}
			if i <= 10 {
				continue
			} else {
				return
			}
		case <-errCh:
			log.Info("read message failed", zap.Error(err))
			return
		}
	}
}
posted @ 2021-12-24 14:36  董大轩  阅读(266)  评论(0编辑  收藏  举报