首页 > 其他分享 >基于 go-zero 框架的项目中集成 WebSocket

基于 go-zero 框架的项目中集成 WebSocket

时间:2024-08-09 15:16:24浏览次数:13  
标签:websocket Connection zero func go WebSocket Config

WebSocket 集成指南

本文档描述了如何在基于 go-zero 框架的项目中集成 WebSocket。

1. 安装依赖

首先,安装 gorilla/websocket 库:

go get github.com/gorilla/websocket

2. 项目结构

在项目中添加以下文件和目录:

└── pkg
    └── websocket
        └── websocket.go

3. WebSocket 实现

pkg/websocket/websocket.go 中实现 WebSocket 处理器:

package websocket

import (
    "net/http"
    "sync"

    "github.com/gorilla/websocket"
    "github.com/zeromicro/go-zero/core/logx"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true // 允许所有来源,您可能需要根据实际情况修改这个检查
    },
}

type Connection struct {
    conn *websocket.Conn
    mu   sync.Mutex
}

type Hub struct {
    connections map[*Connection]bool
    broadcast   chan []byte
    register    chan *Connection
    unregister  chan *Connection
}

func NewHub() *Hub {
    return &Hub{
        connections: make(map[*Connection]bool),
        broadcast:   make(chan []byte),
        register:    make(chan *Connection),
        unregister:  make(chan *Connection),
    }
}

func (h *Hub) Run() {
    for {
        select {
        case conn := <-h.register:
            h.connections[conn] = true
        case conn := <-h.unregister:
            if _, ok := h.connections[conn]; ok {
                delete(h.connections, conn)
                conn.conn.Close()
            }
        case message := <-h.broadcast:
            for conn := range h.connections {
                conn.Write(message)
            }
        }
    }
}

func (c *Connection) Write(message []byte) {
    c.mu.Lock()
    defer c.mu.Unlock()
    err := c.conn.WriteMessage(websocket.TextMessage, message)
    if err != nil {
        logx.Errorf("Error writing message: %v", err)
    }
}

func (h *Hub) HandleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        logx.Errorf("Error upgrading to WebSocket: %v", err)
        return
    }

    c := &Connection{conn: conn}
    h.register <- c

    defer func() {
        h.unregister <- c
    }()

    for {
        _, message, err := conn.ReadMessage()
        if err != nil {
            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
                logx.Errorf("Error reading message: %v", err)
            }
            break
        }
        h.broadcast <- message
    }
}

4. 配置

internal/config/config.go 中添加 WebSocket 配置:

type Config struct {
    rest.RestConf
    WebSocket struct {
        Path string
    }
    // 其他配置...
}

etc/standard-api.yaml 中添加 WebSocket 配置:

WebSocket:
  Path: "/ws"
# 其他配置...

5. 服务上下文集成

internal/svc/service_context.go 中初始化 WebSocket Hub:

type ServiceContext struct {
    Config   config.Config
    WSHub    *websocket.Hub
    // 其他服务...
}

func NewServiceContext(c config.Config) *ServiceContext {
    wsHub := websocket.NewHub()
    go wsHub.Run()

    return &ServiceContext{
        Config:   c,
        WSHub:    wsHub,
        // 初始化其他服务...
    }
}

6. 路由注册

internal/handler/routes.go 中添加 WebSocket 路由:

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
    // 其他路由...

    server.AddRoute(
        rest.Route{
            Method:  http.MethodGet,
            Path:    serverCtx.Config.WebSocket.Path,
            Handler: serverCtx.WSHub.HandleWebSocket,
        },
    )
}

7. 在 Logic 层中使用

internal/logic/standard.go 中使用 WebSocket:

func (l *StandardLogic) BroadcastMessage(message string) {
    l.svcCtx.WSHub.broadcast <- []byte(message)
}

8. 与 Kafka 集成(可选)

如果您想将 Kafka 消息转发到 WebSocket 客户端,可以在 Kafka 消费者处理函数中添加:

func (l *StandardLogic) StartConsumer() error {
    consumer, err := kafka.NewConsumer(l.svcCtx.Config.Kafka.Brokers, consts.ConsumerGroupExample1)
    if err != nil {
        return err
    }
    defer consumer.Close()

    return consumer.Consume(l.ctx, []string{consts.TopicExample1}, func(message *sarama.ConsumerMessage) error {
        // 处理消息
        l.Infof("Received message: %s", string(message.Value))
        
        // 将 Kafka 消息广播到 WebSocket 客户端
        l.BroadcastMessage(string(message.Value))
        
        return nil
    })
}

这样,您就在项目中成功封装了 WebSocket 功能。客户端可以通过配置的 WebSocket 路径(例如 ws://your-server/ws)连接到 WebSocket 服务。您可以在 logic 层中使用 BroadcastMessage 方法向所有连接的客户端发送消息,也可以将 Kafka 消息转发到 WebSocket 客户端。

注意:这个实现是基本的,您可能需要根据具体需求进行进一步的优化和扩展,比如添加身份验证、错误处理、心跳检测等功能。

标签:websocket,Connection,zero,func,go,WebSocket,Config
From: https://www.cnblogs.com/lwhzj/p/18350799

相关文章

  • 编写 Django 单元测试的更优雅的方法
    我目前正在使用Django的单元测试(基于Python标准库模块:unittest)编写测试。我已经为我的Contact模型编写了这个测试,它通过了:classContactTestCase(TestCase):defsetUp(self):"""Createmodelobjects."""Contact.objects.create(nam......
  • 介绍一款新奇的开源操作系统:GodoOS
    在快节奏的现代办公环境中,一款高效、集成化的操作系统无疑是提升工作效率的利器。今天,我们要为您隆重介绍——GodoOS,一款专为内网办公环境设计的全能操作系统。它不仅仅是一个工具,更是您团队协作与文件管理的得力助手,将彻底改变您的工作方式,带来前所未有的便捷体验! 【全能办......
  • 在两个大文件中找出相同的记录,用golang如何写?
    在两个大文件中找出相同的记录,可以使用Golang实现高效的算法。这里主要涉及以下几个步骤:读取文件:逐行读取两个大文件。使用数据结构存储记录:可以使用Go的map数据结构来存储其中一个文件的记录,之后遍历另一个文件,检查其记录是否在map中,若在则记录下该相同记录。输出结果:将......
  • Django+记账管理系统-计算机毕设定制-附项目源码(可白嫖)50377
    摘 要本文课题研究的记账管理系统,系统的主要功能模块包括记账信息、企业类型、公告信息、公告类型等,采取面对对象的开发模式进行软件的开发和硬体的架设,能很好的满足实际使用的需求,完善了对应的软体架设以及程序编码的工作,采用Django开发框架,MySQL数据库,Ajax异步交互,根据Aj......
  • 【优秀python毕设案例】基于python django的新媒体网络舆情数据爬取与分析
    摘   要如今在互联网时代下,微博成为了一种新的流行社交形式,是体现网络舆情的媒介之一。现如今微博舆论多带有虚假不实、恶意造谣等负面舆论,为了营造更好的网络环境,本设计提出了基于新媒体的网络舆情数据爬取与分析,主要对微博热点话题进行处理。本设计首先以Python为环......
  • OCR即时翻译:DeepL和Google两大翻译接口支持,轻便、高效!
    哈喽,大家好!欢迎来到【程序视点】前言OCR识别是日常工作中常用的功能了。大家最常用的应该就是微信截图的OCR功能了。平时用用还好,一旦遇到复杂的,就无法满足我们的要求了。比如今天要说的OCR翻译软件介绍STranslateSTranslate是一款多功能的OCR即时翻译软件,它提供了一种高......
  • 构建即时通讯应用:Spring boot高效集成WebSocket、Stomp协议完成前后端持续通信
    1.引入依赖在你的SpringBoot项目的pom.xml中添加以下依赖:<dependencies><!--SpringBootStarterThymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st......
  • Godot遍历目录下文件,并创建按钮
    想用Godot做一个一站式的文本编辑器核心:funcdir_contents(path): vardir=DirAccess.open(path) varfiles=[] ifdir: dir.list_dir_begin() varfile_name=dir.get_next() whilefile_name!="": ifdir.current_is_dir(): break else: files.......
  • C++ Rect And Point Search Algorithm
    测试 ////Createdbywwwon2024/8/8.//#include"include/cxstructs.h"#include"include/cxml/k-NN.h"//可扩展Rect内搜索子Rect或PointvoidtestRectSearch(){usingnamespacecxstructs;std::random_devicerd;std::mt19937gen(rd()......
  • br4gOnB4ll靶机笔记
    br4gOnB4ll靶机笔记这是一台vulnhub上的免费靶机,比较简单。1、主机发现主机发现-sn只做ping扫描,不做端口扫描nmap-sn192.168.84.1/24StartingNmap7.93(https://nmap.org)at2024-07-0707:37EDTNmapscanreportfor192.168.84.1Hostisup(0.00045slatenc......