初始化项目

This commit is contained in:
皮蛋13361098506
2025-01-06 16:01:02 +08:00
commit 1b77f62820
575 changed files with 69193 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
package websocketUtil
import (
"fmt"
"time"
"github.com/gorilla/websocket"
)
const (
// 最大重试次数
send_max_retry_num int = 60
// 发送错误计数次数
send_error_num int32 = 3
)
type model struct {
wsurl string
msgChan chan *sendModel
con *websocket.Conn
isclose bool
}
type sendModel struct {
data []byte
sendType int
}
// 构造请求对象
func newModel(wsurl string) (*model, error) {
result := &model{}
result.wsurl = wsurl
result.msgChan = make(chan *sendModel, 1000)
// 创建连接
err := result.createCon()
if err != nil {
return nil, err
}
go result.sendhandler()
return result, nil
}
// 发送消息
func (this *model) send(st int, d []byte) {
sm := &sendModel{
data: d,
sendType: st,
}
this.msgChan <- sm
}
// 发送处理器
func (this *model) sendhandler() {
defer func() {
if rerr := recover(); rerr != nil {
errLog("url:%s sendhandler recover:%s", this.wsurl, rerr)
}
}()
// 下面逻辑需要考虑这些情况:
// 1.对端重启 -> 需要尽可能保证消息投递成功
// 2.对端永久关闭 -> 需要尽快释放channel里面的消息以免堵塞channel增加内占用
var err error
var errCount int32
for {
if this.isclose {
return
}
sm := <-this.msgChan
isOk := false
for i := 0; i < send_max_retry_num; i++ {
if this.isclose {
return
}
if this.checkcon() == false {
time.Sleep(time.Second * 1)
debugLog("url:%s channel msgchen 数量达到%v", this.wsurl, len(this.msgChan))
continue
}
err = this.con.WriteMessage(sm.sendType, sm.data)
if err == nil {
isOk = true
break
}
// 记录错误日志
errLog(fmt.Sprintf("wsurl:%s 发送数据错误 err:%s", this.wsurl, err))
this.con = nil
// 如果错误计数到达闸值,则不再重试
if errCount >= send_error_num {
break
} else {
time.Sleep(time.Second)
continue
}
}
// 修改错误计数
if isOk == false {
errCount = errCount + 1
} else {
errCount = 0
}
}
}
func (this *model) closeHandler(code int, text string) error {
debugLog("websocketUtil.model 连接关闭 wsurl:%s code:%v text:%s", this.wsurl, code, text)
this.con = nil
return nil
}
// 创建ws连接
func (this *model) createCon() error {
dd := &websocket.Dialer{
Proxy: websocket.DefaultDialer.Proxy,
HandshakeTimeout: 3 * time.Second,
}
ws, _, err := dd.Dial(this.wsurl, nil)
if err != nil {
return err
}
ws.SetCloseHandler(this.closeHandler)
this.con = ws
return nil
}
// 校验con是否可用
func (this *model) checkcon() bool {
if this.con == nil {
if err := this.createCon(); err != nil {
errLog("wsurl:%s checkcon err:%s", this.wsurl, err)
return false
}
}
return true
}
// close
// @Description: 关闭连接
// @receiver this *model
func (this *model) close() {
close(this.msgChan)
this.isclose = true
debugLog("websocketUtil.model close wsurl:%s", this.wsurl)
}

View File

@@ -0,0 +1,71 @@
package websocketUtil
import (
"errors"
"fmt"
"sync"
)
var (
wsmap sync.Map
errLog func(format string, args ...interface{})
debugLog func(format string, args ...interface{})
)
// SetLog
// @Description:设置日志回调函数信息
// @param errLogFun 错误日志回调函数
// @param debugLogFun debug日志回调函数
func SetLog(errLogFun, debugLogFun func(format string, args ...interface{})) {
errLog = errLogFun
debugLog = debugLogFun
}
// Send
// @Description: 发送数据
// @param wsurl 发送地址
// @param st 发送类型使用websocket下的定义
// @param data 发送数据
// @return error
func Send(wsurl string, st int, data []byte) error {
if debugLog == nil || errLog == nil {
return errors.New("websocketUtil未设置errLog,debugLog回调函数请调用websocketUtil.Setlog函数设置相关信息")
}
m, err := getOrAdd(wsurl)
if err != nil {
errLog(fmt.Sprintf("websocketUtil.Send error:%s", err))
return err
}
m.send(st, data)
return nil
}
// getOrAdd
// @Description:获取或者添加对象
// @param url string
// @return *model
// @return error
func getOrAdd(url string) (*model, error) {
var m *model
var err error
v, isOk := wsmap.Load(url)
if isOk {
m = v.(*model)
return m, nil
}
// 不存在创建对应的socket连接
m, err = newModel(url)
if err != nil {
return nil, err
}
// 保存到map
wsmap.Store(url, m)
return m, err
}