React+Go+WEBSocket
阿新 • • 發佈:2021-12-24
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 } } }